1 //
2 // Copyright 2020 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 INCLUDE_AR_RESOLVER
25 #error This file should not be included directly. Include resolver.h instead.
26 #endif
27 
28 #ifndef PXR_USD_AR_RESOLVER_V1_H
29 #define PXR_USD_AR_RESOLVER_V1_H
30 
31 /// \file ar/resolver_v1.h
32 
33 #include "pxr/pxr.h"
34 #include "pxr/usd/ar/api.h"
35 #include <memory>
36 #include <string>
37 #include <vector>
38 
39 PXR_NAMESPACE_OPEN_SCOPE
40 
41 class ArAsset;
42 class ArAssetInfo;
43 class ArResolverContext;
44 class TfType;
45 class VtValue;
46 
47 /// \class ArResolver
48 ///
49 /// Interface for the asset resolution system. An asset resolver is
50 /// responsible for resolving asset information (including the asset's
51 /// physical path) from a logical path.
52 ///
53 /// See \ref ar_implementing_resolver for information on how to customize
54 /// asset resolution behavior by implementing a subclass of ArResolver.
55 /// Clients may use #ArGetResolver to access the configured asset resolver.
56 ///
57 class ArResolver
58 {
59 public:
60     AR_API
61     virtual ~ArResolver();
62 
63     // Disallow copies
64     ArResolver(const ArResolver&) = delete;
65     ArResolver& operator=(const ArResolver&) = delete;
66 
67     // --------------------------------------------------------------------- //
68     /// \anchor ArResolver_resolution
69     /// \name Path Resolution Operations
70     ///
71     /// @{
72     // --------------------------------------------------------------------- //
73 
74     /// Configures the resolver for a given asset path
75     AR_API
76     virtual void ConfigureResolverForAsset(const std::string& path) = 0;
77 
78     /// Returns the path formed by anchoring \p path to \p anchorPath.
79     ///
80     /// If \p anchorPath ends with a trailing '/', it is treated as
81     /// a directory to which \p path will be anchored. Otherwise, it
82     /// is treated as a file and \p path will be anchored to its
83     /// containing directory.
84     ///
85     /// If \p anchorPath is empty, \p path will be returned as-is.
86     ///
87     /// If \p path is empty or not a relative path, it will be
88     /// returned as-is.
89     AR_API
90     virtual std::string AnchorRelativePath(
91         const std::string& anchorPath,
92         const std::string& path) = 0;
93 
94     /// Returns true if the given path is a relative path.
95     AR_API
96     virtual bool IsRelativePath(const std::string& path) = 0;
97 
98     /// Returns true if the given path is a repository path.
99     AR_API
100     virtual bool IsRepositoryPath(const std::string& path) = 0;
101 
102     /// Returns whether this path is a search path.
103     AR_API
104     virtual bool IsSearchPath(const std::string& path) = 0;
105 
106     /// Returns the normalized extension for the given \p path.
107     AR_API
108     virtual std::string GetExtension(const std::string& path) = 0;
109 
110     /// Returns a normalized version of the given \p path
111     AR_API
112     virtual std::string ComputeNormalizedPath(const std::string& path) = 0;
113 
114     /// Returns the computed repository path using the current resolver
115     AR_API
116     virtual std::string ComputeRepositoryPath(const std::string& path) = 0;
117 
118     /// Returns the local path for the given \p path.
119     AR_API
120     virtual std::string ComputeLocalPath(const std::string& path) = 0;
121 
122     /// Returns the resolved filesystem path for the file identified by
123     /// the given \p path if it exists. If the file does not exist,
124     /// returns an empty string.
125     AR_API
126     virtual std::string Resolve(const std::string& path) = 0;
127 
128     /// @}
129 
130     // --------------------------------------------------------------------- //
131     /// \anchor ArResolver_context
132     /// \name Asset Resolver Context Operations
133     ///
134     /// @{
135     // --------------------------------------------------------------------- //
136 
137     /// Binds the given context to this resolver.
138     ///
139     /// Clients should generally use ArResolverContextBinder instead of calling
140     /// this function directly.
141     ///
142     /// \see ArResolverContextBinder
143     AR_API
144     virtual void BindContext(
145         const ArResolverContext& context,
146         VtValue* bindingData) = 0;
147 
148     /// Unbind the given context from this resolver.
149     ///
150     /// Clients should generally use ArResolverContextBinder instead of calling
151     /// this function directly.
152     ///
153     /// \see ArResolverContextBinder
154     AR_API
155     virtual void UnbindContext(
156         const ArResolverContext& context,
157         VtValue* bindingData) = 0;
158 
159     /// Return a default ArResolverContext that may be bound to this resolver
160     /// to resolve assets when no other context is explicitly specified.
161     ///
162     /// This function should not automatically bind this context, but should
163     /// create one that may be used later.
164     AR_API
165     virtual ArResolverContext CreateDefaultContext() = 0;
166 
167     /// Return a default ArResolverContext that may be bound to this resolver
168     /// to resolve the asset located at \p filePath when no other context is
169     /// explicitly specified.
170     ///
171     /// This function should not automatically bind this context, but should
172     /// create one that may be used later.
173     AR_API
174     virtual ArResolverContext CreateDefaultContextForAsset(
175         const std::string& filePath) = 0;
176 
177     /// Refresh any caches associated with the given context.
178     AR_API
179     virtual void RefreshContext(const ArResolverContext& context) = 0;
180 
181     /// Returns the currently-bound asset resolver context.
182     ///
183     /// \see ArResolver::BindContext, ArResolver::UnbindContext
184     AR_API
185     virtual ArResolverContext GetCurrentContext() = 0;
186 
187     /// @}
188 
189     // --------------------------------------------------------------------- //
190     /// \anchor ArResolver_files
191     /// \name File/asset-specific Operations
192     ///
193     /// @{
194     // --------------------------------------------------------------------- //
195 
196     /// Returns the resolved filesystem path for the file identified
197     /// by \p path following the same path resolution behavior as in
198     /// \ref Resolve(const std::string&).
199     ///
200     /// If the file identified by \p path represents an asset and
201     /// \p assetInfo is not \c nullptr, the resolver should populate
202     /// \p assetInfo with whatever additional metadata it knows or can
203     /// reasonably compute about the asset without actually opening it.
204     ///
205     /// \see Resolve(const std::string&).
206     AR_API
207     virtual std::string ResolveWithAssetInfo(
208         const std::string& path,
209         ArAssetInfo* assetInfo) = 0;
210 
211     /// Update \p assetInfo with respect to the given \p fileVersion .
212     /// \note This API is currently in flux.  In general, you should prefer
213     /// to call ResolveWithAssetInfo()
214     AR_API
215     virtual void UpdateAssetInfo(
216         const std::string& identifier,
217         const std::string& filePath,
218         const std::string& fileVersion,
219         ArAssetInfo* assetInfo) = 0;
220 
221     /// Returns a value representing the last time the asset identified
222     /// by \p path was modified. \p resolvedPath is the resolved path
223     /// of the asset.
224     ///
225     /// Implementations may use whatever value is most appropriate
226     /// for this timestamp. The value must be equality comparable,
227     /// and this function must return a different timestamp whenever
228     /// an asset has been modified. For instance, if an asset is stored
229     /// as a file on disk, the timestamp may simply be that file's mtime.
230     ///
231     /// If a timestamp cannot be retrieved, returns an empty VtValue.
232     AR_API
233     virtual VtValue GetModificationTimestamp(
234         const std::string& path,
235         const std::string& resolvedPath) = 0;
236 
237     /// Fetch the asset identified by \p path to the filesystem location
238     /// specified by \p resolvedPath. \p resolvedPath is the resolved path
239     /// that results from calling Resolve or ResolveWithAssetInfo on
240     /// \p path.
241     ///
242     /// This method provides a way for consumers that expect assets
243     /// to exist as physical files on disk to retrieve data from
244     /// systems that store data in external data stores, e.g. databases,
245     /// etc.
246     ///
247     /// Returns true if the asset was successfully fetched to the specified
248     /// \p resolvedPath or if no fetching was required. If \p resolvedPath
249     /// is not a local path or the asset could not be fetched to that path,
250     /// returns false.
251     AR_API
252     virtual bool FetchToLocalResolvedPath(
253         const std::string& path,
254         const std::string& resolvedPath) = 0;
255 
256     /// Returns an ArAsset object for the asset located at \p resolvedPath.
257     /// Returns an invalid std::shared_ptr if object could not be created.
258     ///
259     /// The returned ArAsset object provides functions for accessing the
260     /// contents of the specified asset.
261     ///
262     /// Note that clients may still be using the data associated with
263     /// this object even after the last shared_ptr has been destroyed. For
264     /// example, a client may have created a memory mapping using the FILE*
265     /// presented in the ArAsset object; this would preclude truncating or
266     /// overwriting any of the contents of that file.
267     AR_API
268     virtual std::shared_ptr<ArAsset> OpenAsset(
269         const std::string& resolvedPath) = 0;
270 
271     /// Create path needed to write a file to the given \p path.
272     ///
273     /// For example:
274     /// - A filesystem-based resolver might create the directories specified
275     ///   in \p path.
276     /// - A database-based resolver might create a new table, or it might
277     ///   ignore this altogether.
278     ///
279     /// In practice, when writing a layer, CanWriteLayerToPath will be called
280     /// first to check if writing is permitted. If this returns true, then
281     /// CreatePathForLayer will be called before writing the layer out.
282     ///
283     /// Returns true on success, false otherwise.
284     AR_API
285     virtual bool CreatePathForLayer(
286         const std::string& path) = 0;
287 
288     /// Returns true if a file may be written to the given \p path, false
289     /// otherwise.
290     ///
291     /// In practice, when writing a layer, CanWriteLayerToPath will be called
292     /// first to check if writing is permitted. If this returns true, then
293     /// CreatePathForLayer will be called before writing the layer out.
294     ///
295     /// If this function returns false and \p whyNot is not \c nullptr,
296     /// it will be filled in with an explanation.
297     AR_API
298     virtual bool CanWriteLayerToPath(
299         const std::string& path,
300         std::string* whyNot) = 0;
301 
302     /// Returns true if a new file may be created using the given
303     /// \p identifier, false otherwise.
304     ///
305     /// If this function returns false and \p whyNot is not \c nullptr,
306     /// it will be filled in with an explanation.
307     AR_API
308     virtual bool CanCreateNewLayerWithIdentifier(
309         const std::string& identifier,
310         std::string* whyNot) = 0;
311 
312     /// @}
313 
314     // --------------------------------------------------------------------- //
315     /// \anchor ArResolver_scopedCache
316     /// \name Scoped Resolution Cache
317     ///
318     /// A scoped resolution cache indicates to the resolver that results of
319     /// calls to Resolve should be cached for a certain scope. This is
320     /// important for performance and also for consistency -- it ensures
321     /// that repeated calls to Resolve with the same parameters will
322     /// return the same result.
323     ///
324     /// A resolution cache scope is opened by a call to BeginCacheScope and
325     /// must be closed with a matching call to EndCacheScope. The resolver must
326     /// cache the results of Resolve until the scope is closed. Note that these
327     /// calls may be nested.
328     ///
329     /// Cache scopes are thread-specific: if multiple threads are running and
330     /// a cache scope is opened in one of those threads, caching should be
331     /// enabled in that thread only.
332     ///
333     /// When opening a scope, a resolver may return additional data for
334     /// implementation-specific purposes. This data may be shared across
335     /// threads, so long as it is safe to access this data concurrently.
336     ///
337     /// ArResolverScopedCache is an RAII object for managing cache scope
338     /// lifetimes and data. Clients should generally use that class rather
339     /// than calling the BeginCacheScope and EndCacheScope functions manually.
340     ///
341     /// \see ArResolverScopedCache
342     /// @{
343     // --------------------------------------------------------------------- //
344 
345     /// Mark the start of a resolution caching scope.
346     ///
347     /// Clients should generally use ArResolverScopedCache instead of calling
348     /// this function directly.
349     ///
350     /// Resolvers may fill \p cacheScopeData with arbitrary data. Clients may
351     /// also pass in a \p cacheScopeData populated by an earlier call to
352     /// BeginCacheScope to allow the resolver access to that information.
353     ///
354     /// \see ArResolverScopedCache
355     AR_API
356     virtual void BeginCacheScope(
357         VtValue* cacheScopeData) = 0;
358 
359     /// Mark the end of a resolution caching scope.
360     ///
361     /// Clients should generally use ArResolverScopedCache instead of calling
362     /// this function directly.
363     ///
364     /// \p cacheScopeData should contain the data that was populated by the
365     /// previous corresponding call to BeginCacheScope.
366     ///
367     /// \see ArResolverScopedCache
368     AR_API
369     virtual void EndCacheScope(
370         VtValue* cacheScopeData) = 0;
371 
372     /// @}
373 
374 protected:
375     AR_API
376     ArResolver();
377 };
378 
379 /// Returns the configured asset resolver.
380 ///
381 /// When first called, this function will determine the ArResolver subclass
382 /// to use for asset resolution via the following process:
383 ///
384 /// - If a preferred resolver has been set via \ref ArSetPreferredResolver,
385 ///   it will be selected.
386 ///
387 /// - Otherwise, a list of available ArResolver subclasses in plugins will
388 ///   be generated. If multiple ArResolver subclasses are found, the list
389 ///   will be sorted by typename. ArDefaultResolver will be added as the last
390 ///   element of this list, and the first resolver in the list will be
391 ///   selected.
392 ///
393 /// - The plugin for the selected subclass will be loaded and an instance
394 ///   of the subclass will be constructed.
395 ///
396 /// - If an error occurs, an ArDefaultResolver will be constructed.
397 ///
398 /// The constructed ArResolver subclass will be cached and used to service
399 /// function calls made on the returned resolver.
400 ///
401 /// Note that this function may not return the constructed subclass itself,
402 /// meaning that dynamic casts to the subclass type may fail. See
403 /// ArGetUnderlyingResolver if access to this object is needed.
404 AR_API
405 ArResolver& ArGetResolver();
406 
407 /// Set the preferred ArResolver subclass used by ArGetResolver.
408 ///
409 /// Consumers may override ArGetResolver's plugin resolver discovery and
410 /// force the use of a specific resolver subclass by calling this
411 /// function with the typename of the implementation to use.
412 ///
413 /// If the subclass specified by \p resolverTypeName cannot be found,
414 /// ArGetResolver will issue a warning and fall back to using
415 /// ArDefaultResolver.
416 ///
417 /// This must be called before the first call to ArGetResolver.
418 AR_API
419 void ArSetPreferredResolver(const std::string& resolverTypeName);
420 
421 /// \name Advanced API
422 ///
423 /// \warning These functions should typically not be used by consumers except
424 /// in very specific cases. Consumers who want to retrieve an ArResolver to
425 /// perform asset resolution should use \ref ArGetResolver.
426 ///
427 /// @{
428 
429 /// Returns the underlying ArResolver instance used by ArGetResolver.
430 ///
431 /// This function returns the instance of the ArResolver subclass used by
432 /// ArGetResolver and can be dynamic_cast to that type.
433 ///
434 /// \warning This functions should typically not be used by consumers except
435 /// in very specific cases. Consumers who want to retrieve an ArResolver to
436 /// perform asset resolution should use \ref ArGetResolver.
437 AR_API
438 ArResolver& ArGetUnderlyingResolver();
439 
440 /// Returns list of TfTypes for available ArResolver subclasses.
441 ///
442 /// This function returns the list of ArResolver subclasses used to determine
443 /// the resolver implementation returned by \ref ArGetResolver. See
444 /// documentation on that function for more details.
445 ///
446 /// If this function is called from within a call (or calls) to
447 /// \ref ArCreateResolver, the ArResolver subclass(es) being created will
448 /// be removed from the returned list.
449 ///
450 /// This function is not safe to call concurrently with itself or
451 /// \ref ArCreateResolver.
452 ///
453 /// \warning This functions should typically not be used by consumers except
454 /// in very specific cases. Consumers who want to retrieve an ArResolver to
455 /// perform asset resolution should use \ref ArGetResolver.
456 AR_API
457 std::vector<TfType> ArGetAvailableResolvers();
458 
459 /// Construct an instance of the ArResolver subclass specified by
460 /// \p resolverType.
461 ///
462 /// This function will load the plugin for the given \p resolverType and
463 /// construct and return a new instance of the specified ArResolver subclass.
464 /// If an error occurs, coding errors will be emitted and this function
465 /// will return an ArDefaultResolver instance.
466 ///
467 /// Note that this function *does not* change the resolver used by
468 /// \ref ArGetResolver to an instance of \p resolverType.
469 ///
470 /// This function is not safe to call concurrently with itself or
471 /// \ref ArGetAvailableResolvers.
472 ///
473 /// \warning This functions should typically not be used by consumers except
474 /// in very specific cases. Consumers who want to retrieve an ArResolver to
475 /// perform asset resolution should use \ref ArGetResolver.
476 AR_API
477 std::unique_ptr<ArResolver> ArCreateResolver(const TfType& resolverType);
478 
479 /// @}
480 
481 PXR_NAMESPACE_CLOSE_SCOPE
482 
483 #endif
484