1 //
2 // Copyright 2016 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 #ifndef PXR_USD_USD_SCHEMA_REGISTRY_H
25 #define PXR_USD_USD_SCHEMA_REGISTRY_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/usd/api.h"
29 #include "pxr/usd/usd/common.h"
30 
31 #include "pxr/usd/sdf/layer.h"
32 #include "pxr/usd/sdf/primSpec.h"
33 
34 #include "pxr/base/tf/hash.h"
35 #include "pxr/base/tf/singleton.h"
36 
37 #include <unordered_map>
38 
39 PXR_NAMESPACE_OPEN_SCOPE
40 
41 SDF_DECLARE_HANDLES(SdfAttributeSpec);
42 SDF_DECLARE_HANDLES(SdfRelationshipSpec);
43 
44 class UsdPrimDefinition;
45 
46 /// \class UsdSchemaRegistry
47 ///
48 /// Singleton registry that provides access to schema type information and
49 /// the prim definitions for registered Usd "IsA" and applied API schema
50 /// types. It also contains the data from the generated schemas that is used
51 /// by prim definitions to provide properties and fallbacks.
52 ///
53 /// The data contained herein comes from the generatedSchema.usda file
54 /// (generated when a schema.usda file is processed by \em usdGenSchema)
55 /// of each schema-defining module. The registry expects each schema type to
56 /// be represented as a single prim spec with its inheritance flattened, i.e.
57 /// the prim spec contains a union of all its local and class inherited property
58 /// specs and metadata fields.
59 ///
60 /// It is used by the Usd core, via UsdPrimDefinition, to determine how to
61 /// create scene description for unauthored "built-in" properties of schema
62 /// classes, to enumerate all properties for a given schema class, and finally
63 /// to provide fallback values for unauthored built-in properties.
64 ///
65 class UsdSchemaRegistry : public TfWeakBase, boost::noncopyable {
66 public:
67     USD_API
GetInstance()68     static UsdSchemaRegistry& GetInstance() {
69         return TfSingleton<UsdSchemaRegistry>::GetInstance();
70     }
71 
72     /// Return the type name in the USD schema for prims or API schemas of the
73     /// given registered \p schemaType.
74     USD_API
75     static TfToken GetSchemaTypeName(const TfType &schemaType);
76 
77     /// Return the type name in the USD schema for prims or API schemas of the
78     /// given registered \p SchemaType.
79     template <class SchemaType>
80     static
GetSchemaTypeName()81     TfToken GetSchemaTypeName() {
82         return GetSchemaTypeName(SchemaType::_GetStaticTfType());
83     }
84 
85     /// Return the type name in the USD schema for concrete prim types only from
86     /// the given registered \p schemaType.
87     USD_API
88     static TfToken GetConcreteSchemaTypeName(const TfType &schemaType);
89 
90     /// Return the type name in the USD schema for API schema types only from
91     /// the given registered \p schemaType.
92     USD_API
93     static TfToken GetAPISchemaTypeName(const TfType &schemaType);
94 
95     /// Return the TfType of the schema corresponding to the given prim or API
96     /// schema name \p typeName. This the inverse of GetSchemaTypeName.
97     USD_API
98     static TfType GetTypeFromSchemaTypeName(const TfToken &typeName);
99 
100     /// Return the TfType of the schema corresponding to the given concrete prim
101     /// type name \p typeName. This the inverse of GetConcreteSchemaTypeName.
102     USD_API
103     static TfType GetConcreteTypeFromSchemaTypeName(const TfToken &typeName);
104 
105     /// Return the TfType of the schema corresponding to the given API schema
106     /// type name \p typeName. This the inverse of GetAPISchemaTypeNAme.
107     USD_API
108     static TfType GetAPITypeFromSchemaTypeName(const TfToken &typeName);
109 
110     /// Returns true if the field \p fieldName cannot have fallback values
111     /// specified in schemas.
112     ///
113     /// Fields are generally disallowed because their fallback values
114     /// aren't used. For instance, fallback values for composition arcs
115     /// aren't used during composition, so allowing them to be set in
116     /// schemas would be misleading.
117     USD_API
118     static bool IsDisallowedField(const TfToken &fieldName);
119 
120     /// Returns true if the prim type \p primType inherits from \ref UsdTyped.
121     USD_API
122     static bool IsTyped(const TfType& primType);
123 
124     /// Returns the kind of the schema the given \p schemaType represents.
125     ///
126     /// This returns UsdSchemaKind::Invalid if \p schemaType is not a valid
127     /// schema type or if the kind cannot be determined from type's plugin
128     /// information.
129     USD_API
130     static UsdSchemaKind GetSchemaKind(const TfType &schemaType);
131 
132     /// Returns the kind of the schema the given \p typeName represents.
133     ///
134     /// This returns UsdSchemaKind::Invalid if \p typeName is not a valid
135     /// schema type name or if the kind cannot be determined from type's plugin
136     /// information.
137     USD_API
138     static UsdSchemaKind GetSchemaKind(const TfToken &typeName);
139 
140     /// Returns true if the prim type \p primType is instantiable
141     /// in scene description.
142     USD_API
143     static bool IsConcrete(const TfType& primType);
144 
145     /// Returns true if the prim type \p primType is instantiable
146     /// in scene description.
147     USD_API
148     static bool IsConcrete(const TfToken& primType);
149 
150     /// Returns true if \p apiSchemaType is an applied API schema type.
151     USD_API
152     static bool IsAppliedAPISchema(const TfType& apiSchemaType);
153 
154     /// Returns true if \p apiSchemaType is an applied API schema type.
155     USD_API
156     static bool IsAppliedAPISchema(const TfToken& apiSchemaType);
157 
158     /// Returns true if \p apiSchemaType is a multiple-apply API schema type.
159     USD_API
160     static bool IsMultipleApplyAPISchema(const TfType& apiSchemaType);
161 
162     /// Returns true if \p apiSchemaType is a multiple-apply API schema type.
163     USD_API
164     static bool IsMultipleApplyAPISchema(const TfToken& apiSchemaType);
165 
166     /// Finds the TfType of a schema with \p typeName
167     ///
168     /// This is primarily for when you have been provided Schema typeName
169     /// (perhaps from a User Interface or Script) and need to identify
170     /// if a prim's type inherits/is that typeName. If the type name IS known,
171     /// then using the schema class is preferred.
172     ///
173     /// \code{.py}
174     /// # This code attempts to match all prims on a stage to a given
175     /// # user specified type, making the traditional schema based idioms not
176     /// # applicable.
177     /// data = parser.parse_args()
178     /// tfType = UsdSchemaRegistry.GetTypeFromName(data.type)
179     /// matchedPrims = [p for p in stage.Traverse() if p.IsA(tfType)]
180     /// \endcode
181     ///
182     /// \note It's worth noting that
183     /// GetTypeFromName("Sphere") == GetTypeFromName("UsdGeomSphere"), as
184     /// this function resolves both the Schema's C++ class name and any
185     /// registered aliases from a libraries plugInfo.json file. However,
186     /// GetTypeFromName("Boundable") != GetTypeFromName("UsdGeomBoundable")
187     /// because type aliases don't get registered for abstract schema types.
188     USD_API
189     static TfType GetTypeFromName(const TfToken& typeName);
190 
191     /// Returns the schema type name and the instance name parsed from the
192     /// given \p apiSchemaName
193     ///
194     /// \p apiSchemaName is the name of an applied schema as it appears in
195     /// the list of applied schemas on a prim. For single-apply API schemas
196     /// the name will just be the schema type name. For multiple-apply schemas
197     /// the name should include the schema type name and the applied instance
198     /// name separated by a namespace delimiter, for example
199     /// 'CollectionAPI:plasticStuff'.
200     ///
201     /// This function returns the separated schema type name and instance name
202     /// component tokens if possible, otherwise it returns the \p apiSchemaName
203     /// as the type name and an empty instance name.
204     ///
205     /// Note that no validation is done on the returned tokens. Clients are
206     /// advised to use GetTypeFromSchemaTypeName() to validate the typeName
207     /// token.
208     ///
209     /// \sa UsdPrim::AddAppliedSchema(const TfToken&) const
210     /// \sa UsdPrim::GetAppliedSchemas() const
211     USD_API
212     static std::pair<TfToken, TfToken> GetTypeNameAndInstance(
213             const TfToken &apiSchemaName);
214 
215     /// Returns true if the given \p instanceName is an allowed instance name
216     /// for the multiple apply API schema named \p apiSchemaName.
217     ///
218     /// Any instance name that matches the name of a property provided by the
219     /// API schema is disallowed and will return false. If the schema type
220     /// has plugin metadata that specifies allowed instance names, then only
221     /// those specified names are allowed for the schema type.
222     /// If the instance name is empty or the API is not a multiple apply schema,
223     /// this will return false.
224     USD_API
225     static bool IsAllowedAPISchemaInstanceName(
226         const TfToken &apiSchemaName,
227         const TfToken &instanceName);
228 
229     /// Returns a list of prim type names that the given \p apiSchemaName can
230     /// only be applied to.
231     ///
232     /// A non-empty list indicates that the API schema can only be applied to
233     /// prim that are or derive from prim type names in the list. If the list
234     /// is empty, the API schema can be applied to prims of any type.
235     ///
236     /// If a non-empty \p instanceName is provided, this will first look for
237     /// a list of "can only apply to" names specific to that instance of the API
238     /// schema and return that if found. If a list is not found for the specific
239     /// instance, it will fall back to looking for a "can only apply to" list
240     /// for just the schema name itself.
241     USD_API
242     static const TfTokenVector &GetAPISchemaCanOnlyApplyToTypeNames(
243         const TfToken &apiSchemaName,
244         const TfToken &instanceName = TfToken());
245 
246     /// Returns a map of the names of all registered auto apply API schemas
247     /// to the list of type names each is registered to be auto applied to.
248     ///
249     /// The list of type names to apply to will directly match what is specified
250     /// in the plugin metadata for each schema type. While auto apply schemas do
251     /// account for the existence and validity of the type names and expand to
252     /// include derived types of the listed types, the type lists returned by
253     /// this function do not.
254     USD_API
255     static const std::map<TfToken, TfTokenVector> &GetAutoApplyAPISchemas();
256 
257     /// Collects all the additional auto apply schemas that can be defined in
258     /// a plugin through "AutoApplyAPISchemas" metadata and adds the mappings
259     /// to \p autoApplyAPISchemas.
260     ///
261     /// These are separate from the auto-apply schemas that are built in to the
262     /// applied API schema types themselves and can be defined in any plugin to
263     /// map any applied API schema to any concrete prim type.
264     ///
265     /// Note that GetAutoApplyAPISchemas will already include API schemas
266     /// collected from this method; this function is provided for clients that
267     /// may want to collect just these plugin API schema mappings.
268     USD_API
269     static void CollectAddtionalAutoApplyAPISchemasFromPlugins(
270         std::map<TfToken, TfTokenVector> *autoApplyAPISchemas);
271 
272     /// Returns the namespace prefix that is prepended to all properties of
273     /// the given \p multiApplyAPISchemaName.
274     USD_API
275     TfToken GetPropertyNamespacePrefix(
276         const TfToken &multiApplyAPISchemaName) const;
277 
278     /// Finds the prim definition for the given \p typeName token if
279     /// \p typeName is a registered concrete typed schema type. Returns null if
280     /// it is not.
FindConcretePrimDefinition(const TfToken & typeName)281     const UsdPrimDefinition* FindConcretePrimDefinition(
282         const TfToken &typeName) const {
283         const auto it = _concreteTypedPrimDefinitions.find(typeName);
284         return it != _concreteTypedPrimDefinitions.end() ? it->second : nullptr;
285     }
286 
287     /// Finds the prim definition for the given \p typeName token if
288     /// \p typeName is a registered applied API schema type. Returns null if
289     /// it is not.
FindAppliedAPIPrimDefinition(const TfToken & typeName)290     const UsdPrimDefinition *FindAppliedAPIPrimDefinition(
291         const TfToken &typeName) const {
292         // Check the single apply API schemas first then check for multiple
293         // apply schemas. This function will most often be used to find a
294         // single apply schema's prim definition as the prim definitions for
295         // multiple apply schemas aren't generally useful.
296         const auto it = _singleApplyAPIPrimDefinitions.find(typeName);
297         if (it != _singleApplyAPIPrimDefinitions.end()) {
298             return it->second;
299         }
300         const auto multiIt = _multiApplyAPIPrimDefinitions.find(typeName);
301         return multiIt != _multiApplyAPIPrimDefinitions.end() ?
302             multiIt->second.primDef : nullptr;
303     }
304 
305     /// Returns the empty prim definition.
GetEmptyPrimDefinition()306     const UsdPrimDefinition *GetEmptyPrimDefinition() const {
307         return _emptyPrimDefinition;
308     }
309 
310     /// Composes and returns a new UsdPrimDefinition from the given \p primType
311     /// and list of \p appliedSchemas. This prim definition will contain a union
312     /// of properties from the registered prim definitions of each of the
313     /// provided types.
314     USD_API
315     std::unique_ptr<UsdPrimDefinition>
316     BuildComposedPrimDefinition(
317         const TfToken &primType, const TfTokenVector &appliedAPISchemas) const;
318 
319     /// Returns a dictionary mapping concrete schema prim type names to a
320     /// VtTokenArray of fallback prim type names if fallback types are defined
321     /// for the schema type in its registered schema.
322     ///
323     /// The standard use case for this to provide schema defined metadata that
324     /// can be saved with a stage to inform an older version of USD - that
325     /// may not have some schema types - as to which types it can used instead
326     /// when encountering a prim of one these types.
327     ///
328     /// \sa UsdStage::WriteFallbackPrimTypes
329     /// \sa \ref Usd_OM_FallbackPrimTypes
GetFallbackPrimTypes()330     const VtDictionary &GetFallbackPrimTypes() const {
331         return _fallbackPrimTypes;
332     }
333 
334 private:
335     friend class TfSingleton<UsdSchemaRegistry>;
336 
337     UsdSchemaRegistry();
338 
339     // For the given full API schema name (which may be "type:instance" for
340     // multiple apply API schemas), finds and returns the prim definition for
341     // the API schema type. If the API schema is an instance of a multiple
342     // apply API, the full prefix that will be prepended to all properties
343     // when the schema is applied will be set in propertyPrefix.
344     const UsdPrimDefinition *_FindAPIPrimDefinitionByFullName(
345         const TfToken &apiSchemaName, std::string *propertyPrefix) const;
346 
347     void _ComposeAPISchemasIntoPrimDefinition(
348         UsdPrimDefinition *primDef,
349         const TfTokenVector &appliedAPISchemas) const;
350 
351     // Private class for helping initialize the schema registry. Defined
352     // entirely in the implementation. Declared here for private access to the
353     // registry.
354     class _SchemaDefInitHelper;
355 
356     // Multiple apply API schema definitions want to be stored along with the
357     // their schema's property namespace prefix which is required to correctly
358     // apply them.
359     struct _MultipleApplyAPIDefinition {
360         UsdPrimDefinition *primDef = nullptr;
361         TfToken propertyNamespace;
362     };
363     using _TypeNameToMultipleApplyAPIDefinitionMap = std::unordered_map<
364         TfToken, _MultipleApplyAPIDefinition, TfToken::HashFunctor>;
365 
366     using _TypeNameToPrimDefinitionMap = std::unordered_map<
367         TfToken, UsdPrimDefinition *, TfToken::HashFunctor>;
368 
369     SdfLayerRefPtr _schematics;
370 
371     _TypeNameToPrimDefinitionMap _concreteTypedPrimDefinitions;
372     _TypeNameToPrimDefinitionMap _singleApplyAPIPrimDefinitions;
373     _TypeNameToMultipleApplyAPIDefinitionMap _multiApplyAPIPrimDefinitions;
374     UsdPrimDefinition *_emptyPrimDefinition;
375 
376     VtDictionary _fallbackPrimTypes;
377 
378     friend class UsdPrimDefinition;
379 };
380 
381 USD_API_TEMPLATE_CLASS(TfSingleton<UsdSchemaRegistry>);
382 
383 // Utility function for extracting the metadata about applying API schemas from
384 // the plugin metadata for the schema's type. It is useful for certain clients
385 // to be able to access this plugin data in the same way that the
386 // UsdSchemaRegistry does.
387 void Usd_GetAPISchemaPluginApplyToInfoForType(
388     const TfType &apiSchemaType,
389     const TfToken &apiSchemaName,
390     std::map<TfToken, TfTokenVector> *autoApplyAPISchemasMap,
391     TfHashMap<TfToken, TfTokenVector, TfHash> *canOnlyApplyAPISchemasMap,
392     TfHashMap<TfToken, TfToken::Set, TfHash> *allowedInstanceNamesMap);
393 
394 PXR_NAMESPACE_CLOSE_SCOPE
395 
396 #endif //PXR_USD_USD_SCHEMA_REGISTRY_H
397