HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
registry.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_PLUG_REGISTRY_H
8 #define PXR_BASE_PLUG_REGISTRY_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/base/plug/api.h"
12 
13 #include "pxr/base/js/value.h"
15 #include "pxr/base/tf/hash.h"
16 #include "pxr/base/tf/hashset.h"
17 #include "pxr/base/tf/refPtr.h"
18 #include "pxr/base/tf/singleton.h"
19 #include "pxr/base/tf/type.h"
20 #include "pxr/base/tf/weakBase.h"
21 #include "pxr/base/tf/weakPtr.h"
22 
23 #include <mutex>
24 #include <string>
25 #include <vector>
26 
28 
30 class Plug_RegistrationMetadata;
31 
32 /// \class PlugRegistry
33 ///
34 /// Defines an interface for registering plugins.
35 ///
36 /// PlugRegistry maintains a registry of plug-ins known to the system
37 /// and provides an interface for base classes to load any plug-ins required
38 /// to instantiate a subclass of a given type.
39 ///
40 /// <h2>Defining a Base Class API</h2>
41 ///
42 /// In order to use this facility you will generally provide a library
43 /// which defines the API for a plug-in base class. This API
44 /// will be sufficient for the application or framework to make use of
45 /// custom subclasses that will be written by plug-in developers.
46 ///
47 /// For example, if you have an image processing application, you might
48 /// want to support plug-ins that implement image filters. You can define
49 /// an abstract base class for image filters that declares the API your
50 /// application will require image filters to implement; perhaps something
51 /// simple like \ref plug_cppcode_PlugRegistry1 "C++ Code Example 1" (Doxygen only).
52 ///
53 /// People writing custom filters would write a subclass of ImageFilter that
54 /// overrides the two methods, implementing their own special filtering
55 /// behavior.
56 ///
57 /// \section plug_EnablingPlugins Enabling Plug-in Loading for the Base Class
58 ///
59 /// In order for ImageFilter to be able to load plug-ins that implement
60 /// these custom subclasses, it must be registered with the TfType system.
61 ///
62 /// The ImageFilter base class, as was mentioned earlier, should be made
63 /// available in a library that the application links with. This is done
64 /// so that plug-ins that want to provide ImageFilters can also link with
65 /// the library allowing them to subclass ImageFilter.
66 ///
67 /// \section plug_RegisteringPlugins Registering Plug-ins
68 ///
69 /// A plug-in developer can now write plug-ins with ImageFilter subclasses.
70 /// Plug-ins can be implemented either as native dynamic libraries (either
71 /// regular dynamic libraries or framework bundles) or as Python modules.
72 ///
73 /// Plug-ins must be registered with the registry. All plugins are
74 /// registered via RegisterPlugins(). Plug-in Python modules must be
75 /// directly importable (in other words they must be able to be found in
76 /// Python's module path.) Plugins are registered by providing a path or
77 /// paths to JSON files that describe the location, structure and contents
78 /// of the plugin. The standard name for these files in plugInfo.json.
79 ///
80 /// Typically, the application that hosts plug-ins will locate and register
81 /// plug-ins at startup.
82 ///
83 /// The plug-in facility is lazy. It does not dynamically load code from
84 /// plug-in bundles until that code is required.
85 ///
86 /// \section plug_plugInfo plugInfo.json
87 ///
88 /// A plugInfo.json file has the following structure:
89 ///
90 /// \code
91 /// {
92 /// # Comments are allowed and indicated by a hash at the start of a
93 /// # line or after spaces and tabs. They continue to the end of line.
94 /// # Blank lines are okay, too.
95 ///
96 /// # This is optional. It may contain any number of strings.
97 /// # Paths may be absolute or relative.
98 /// # Paths ending with slash have plugInfo.json appended automatically.
99 /// # '*' may be used anywhere to match any character except slash.
100 /// # '**' may be used anywhere to match any character including slash.
101 /// "Includes": [
102 /// "/absolute/path/to/plugInfo.json",
103 /// "/absolute/path/to/custom.filename",
104 /// "/absolute/path/to/directory/with/plugInfo/",
105 /// "relative/path/to/plugInfo.json",
106 /// "relative/path/to/directory/with/plugInfo/",
107 /// "glob*/pa*th/*to*/*/plugInfo.json",
108 /// "recursive/pa**th/**/"
109 /// ],
110 ///
111 /// # This is optional. It may contain any number of objects.
112 /// "Plugins": [
113 /// {
114 /// # Type is required and may be "library", "python" or "resource".
115 /// "Type": "library",
116 ///
117 /// # Name is required. It should be the Python module name,
118 /// # the shared library name, or a unique resource name.
119 /// "Name": "myplugin",
120 ///
121 /// # Root is optional. It defaults to ".".
122 /// # This gives the path to the plugin as a whole if the plugin
123 /// # has substructure. For Python it should be the directory
124 /// # with the __init__.py file. The path is usually relative.
125 /// "Root": ".",
126 ///
127 /// # LibraryPath is required by Type "library" and unused
128 /// # otherwise. It gives the path to the shared library
129 /// # object, either absolute or relative to Root.
130 /// "LibraryPath": "libmyplugin.so",
131 ///
132 /// # ResourcePath is option. It defaults to ".".
133 /// # This gives the path to the plugin's resources directory.
134 /// # The path is either absolute or relative to Root.
135 /// "ResourcePath": "resources",
136 ///
137 /// # Info is required. It's described below.
138 /// "Info": {
139 /// # Plugin contents.
140 /// }
141 /// }
142 /// ]
143 /// }
144 /// \endcode
145 ///
146 /// As a special case, if a plugInfo.json contains an object that doesn't
147 /// have either the "Includes" or "Plugins" keys then it's as if the object
148 /// was in a "Plugins" array.
149 ///
150 /// \section plug_Advertising Advertising a Plug-in's Contents
151 ///
152 /// Once the plug-ins are registered, the plug-in facility must also be
153 /// able to tell what they contain. Specifically, it must be able to find
154 /// out what subclasses of what plug-in base classes each plug-in contains.
155 /// Plug-ins must advertise this information through their plugInfo.json file
156 /// in the "Info" key. In the "Info" object there should be a key "Types"
157 /// holding an object.
158 ///
159 /// This "Types" object's keys are names of subclasses and its values are yet
160 /// more objects (the subclass meta-data objects). The meta-data objects can
161 /// contain arbitrary key-value pairs. The plug-in mechanism will look for a
162 /// meta-data key called "displayName" whose value should be the display name
163 /// of the subclass. The plug-in mechanism will look for a meta-data key
164 /// called "bases" whose value should be an array of base class type names.
165 ///
166 /// For example, a bundle that contains a subclass of ImageFilter might have
167 /// a plugInfo.json that looks like the following example.
168 ///
169 /// \code
170 /// {
171 /// "Types": {
172 /// "MyCustomCoolFilter" : {
173 /// "bases": ["ImageFilter"],
174 /// "displayName": "Add Coolness to Image"
175 /// # other arbitrary metadata for MyCustomCoolFilter here
176 /// }
177 /// }
178 /// }
179 /// \endcode
180 ///
181 /// What this says is that the plug-in contains a type called MyCustomCoolFilter
182 /// which has a base class ImageFilter and that this subclass should be called
183 /// "Add Coolness to Image" in user-visible contexts.
184 ///
185 /// In addition to the "displayName" meta-data key which is actually
186 /// known to the plug-in facility, you may put whatever other information
187 /// you want into a class' meta-data dictionary. If your plug-in base class
188 /// wants to define custom keys that it requires all subclasses to provide,
189 /// you can do that. Or, if a plug-in writer wants to define their own keys
190 /// that their code will look for at runtime, that is OK as well.
191 ///
192 /// \section plug_subClasses Working with Subclasses of a Plug-in Base Class
193 ///
194 /// Most code with uses types defined in plug-ins doesn't deal with
195 /// the Plug API directly. Instead, the TfType interface is used
196 /// to lookup types and to manufacture instances. The TfType interface
197 /// will take care to load any required plugins.
198 ///
199 /// To wrap up our example, the application that wants to actually use
200 /// ImageFilter plug-ins would probably do a couple of things. First, it
201 /// would get a list of available ImageFilters to present to the user.
202 /// This could be accomplished as shown in
203 /// \ref plug_cppcode_PlugRegistry2 "Python Code Example 2" (Doxygen only).
204 ///
205 /// Then, when the user picks a filter from the list, it would manufacture
206 /// and instance of the filter as shown in
207 /// \ref plug_cppcode_PlugRegistry3 "Python Code Example 3" (Doxygen only).
208 ///
209 /// As was mentioned earlier, this plug-in facility tries to be as lazy
210 /// as possible about loading the code associated with plug-ins. To that end,
211 /// loading of a plugin will be deferred until an instance of a type
212 /// is manufactured which requires the plugin.
213 ///
214 /// \section plug_MultipleSubclasses Multiple Subclasses of Multiple Plug-in Base Classes
215 ///
216 /// It is possible for a bundle to implement multiple subclasses
217 /// for a plug-in base class if desired. If you want to package half a dozen
218 /// ImageFilter subclasses in one bundle, that will work fine. All must
219 /// be declared in the plugInfo.json.
220 ///
221 /// It is possible for there to be multiple classes in your
222 /// application or framework that are plug-in base classes. Plug-ins that
223 /// implement subclasses of any of these base classes can all coexist. And,
224 /// it is possible to have subclasses of multiple plug-in base classes in the
225 /// same bundle.
226 ///
227 /// When putting multiple subclasses (of the same or different base classes)
228 /// in a bundle, keep in mind that dynamic loading happens for the whole bundle
229 /// the first time any subclass is needed, the whole bundle will be loaded.
230 /// But this is generally not a big concern.
231 ///
232 /// For example, say the example application also has a plug-in base class
233 /// "ImageCodec" that allows people to add support for reading and writing
234 /// other image formats. Imagine that you want to supply a plug-in that
235 /// has two codecs and a filter all in a single plug-in. Your plugInfo.json
236 /// "Info" object might look something like this example.
237 ///
238 /// \code
239 /// {
240 /// "Types": {
241 /// "MyTIFFCodec": {
242 /// "bases": ["ImageCodec"],
243 /// "displayName": "TIFF Image"
244 /// },
245 /// "MyJPEGCodec": {
246 /// "bases": ["ImageCodec"],
247 /// "displayName": "JPEG Image"
248 /// },
249 /// "MyCustomCoolFilter" : {
250 /// "bases": ["ImageFilter"],
251 /// "displayName": "Add Coolness to Image"
252 /// }
253 /// }
254 /// }
255 /// \endcode
256 ///
257 /// \section plug_Dependencies Dependencies on Other Plug-ins
258 ///
259 /// If you write a plug-in that has dependencies on another plug-in that you
260 /// cannot (or do not want to) link against statically, you can declare
261 /// the dependencies in your plug-in's plugInfo.json . A plug-in declares
262 /// dependencies on other classes with a PluginDependencies key whose value
263 /// is a dictionary. The keys of the dictionary are plug-in base class names
264 /// and the values are arrays of subclass names.
265 ///
266 /// The following example contains an example of a plug-in that depends on two
267 /// classes from the plug-in in the previous example.
268 ///
269 /// \code
270 /// {
271 /// "Types": {
272 /// "UltraCoolFilter": {
273 /// "bases": ["MyCustomCoolFilter"],
274 /// "displayName": "Add Unbelievable Coolness to Image"
275 /// # A subclass of MyCustomCoolFilter that also uses MyTIFFCodec
276 /// }
277 /// },
278 /// "PluginDependencies": {
279 /// "ImageFilter": ["MyCustomCoolFilter"],
280 /// "ImageCodec": ["MyTIFFCodec"]
281 /// }
282 /// }
283 /// \endcode
284 ///
285 /// The ImageFilter provided by the plug-in in this example depends on the
286 /// other ImageFilter MyCoolImageFilter and the ImageCodec MyTIFFCodec.
287 /// Before loading this plug-in, the plug-in facility will ensure that those
288 /// two classes are present, loading the plug-in that contains them if needed.
289 ///
290 /// \section plug_cppcode_PlugRegistry1 C++ Code Example 1
291 /// \code
292 /// // Declare a base class interface
293 /// class ImageFilter {
294 /// public:
295 /// virtual bool CanFilterImage(const ImagePtr & inputImage) = 0;
296 /// virtual ImagePtr FilterImage(const ImagePtr & inputImage) = 0;
297 /// };
298 /// \endcode
299 ///
300 /// \section plug_cppcode_PlugRegistry2 Python Code Example 2
301 /// \code
302 /// # Get the names of derived types
303 /// baseType = Tf.Type.Find(ImageFilter)
304 /// if baseType:
305 /// derivedTypes = baseType.GetAllDerived()
306 /// derivedTypeNames = [ derived.typeName for derived in derivedTypes ]
307 /// \endcode
308 ///
309 /// \section plug_cppcode_PlugRegistry3 Python Code Example 3
310 /// \code
311 /// # Manufacture an instance of a derived type
312 /// imageFilterType = Tf.Type.Find(ImageFilter)
313 /// myFilterType = Tf.Type.FindByName('UltraCoolImageFilter')
314 /// if myFilterType and myFilterType.IsA(imageFilterType):
315 /// myFilter = myFilterType.Manufacture()
316 /// \endcode
317 ///
318 
319 class PlugRegistry : public TfWeakBase {
320  PlugRegistry(PlugRegistry const &) = delete;
321  PlugRegistry &operator=(PlugRegistry const &) = delete;
322 public:
324  typedef std::vector<TfType> TypeVector;
325 
326  /// Returns the singleton \c PlugRegistry instance.
327  PLUG_API
328  static PlugRegistry & GetInstance();
329 
330  /// Registers all plug-ins discovered at \a pathToPlugInfo. Sends
331  /// PlugNotice::DidRegisterPlugins with any newly registered plugins.
332  PLUG_API
333  PlugPluginPtrVector RegisterPlugins(const std::string & pathToPlugInfo);
334 
335  /// Registers all plug-ins discovered in any of \a pathsToPlugInfo. Sends
336  /// PlugNotice::DidRegisterPlugins with any newly registered plugins.
337  PLUG_API
338  PlugPluginPtrVector
339  RegisterPlugins(const std::vector<std::string> & pathsToPlugInfo);
340 
341  /// Retrieve the \c TfType corresponding to the given \c name. See the
342  /// documentation for \c TfType::FindByName for more information. Use this
343  /// function if you expect that \c name may name a type provided by a
344  /// plugin. Calling this function will incur plugin discovery (but not
345  /// loading) if plugin discovery has not yet occurred.
346  ///
347  /// Note that additional plugins may be registered during program runtime.
348  /// \sa \ref Plug_Discovery
349  PLUG_API
350  static TfType FindTypeByName(std::string const &typeName);
351 
352  /// Retrieve the \c TfType that derives from \c base and has the given alias
353  /// or type name \c typeName. See the documentation for \c
354  /// TfType::FindDerivedByName for more information. Use this function if
355  /// you expect that the derived type may be provided by a plugin. Calling
356  /// this function will incur plugin discovery (but not loading) if plugin
357  /// discovery has not yet occurred.
358  ///
359  /// Note that additional plugins may be registered during program runtime.
360  /// \sa \ref Plug_Discovery
361  PLUG_API
362  static TfType
363  FindDerivedTypeByName(TfType base, std::string const &typeName);
364 
365  /// Retrieve the \c TfType that derives from \c Base and has the given alias
366  /// or type name \c typeName. See the documentation for \c
367  /// TfType::FindDerivedByName for more information. Use this function if
368  /// you expect that the derived type may be provided by a plugin. Calling
369  /// this function will incur plugin discovery (but not loading) if plugin
370  /// discovery has not yet occurred.
371  ///
372  /// Note that additional plugins may be registered during program runtime.
373  /// \sa \ref Plug_Discovery
374  template <class Base>
375  static TfType
376  FindDerivedTypeByName(std::string const &typeName) {
377  return FindDerivedTypeByName(TfType::Find<Base>(), typeName);
378  }
379 
380  /// Return a vector of types derived directly from \a base. Use this
381  /// function if you expect that plugins may provide types derived from \a
382  /// base. Otherwise, use \a TfType::GetDirectlyDerivedTypes.
383  ///
384  PLUG_API
385  static std::vector<TfType>
387 
388  /// Return the set of all types derived (directly or indirectly) from
389  /// \a base. Use this function if you expect that plugins may provide types
390  /// derived from \a base. Otherwise, use \a TfType::GetAllDerivedTypes.
391  ///
392  /// Note that additional plugins may be registered during program runtime.
393  /// \sa \ref Plug_Discovery
394  PLUG_API
395  static void
396  GetAllDerivedTypes(TfType base, std::set<TfType> *result);
397 
398  /// Return the set of all types derived (directly or indirectly) from
399  /// \a Base. Use this function if you expect that plugins may provide types
400  /// derived from \a base. Otherwise, use \a TfType::GetAllDerivedTypes.
401  ///
402  /// Note that additional plugins may be registered during program runtime.
403  /// \sa \ref Plug_Discovery
404  template <class Base>
405  static void
406  GetAllDerivedTypes(std::set<TfType> *result) {
407  return GetAllDerivedTypes(TfType::Find<Base>(), result);
408  }
409 
410  /// Returns the plug-in for the given type, or a null pointer if there is no
411  /// registered plug-in.
412  PLUG_API
413  PlugPluginPtr GetPluginForType(TfType t) const;
414 
415  /// Returns all registered plug-ins. Note that additional plugins may be
416  /// registered during program runtime. \sa \ref Plug_Discovery
417  PLUG_API
418  PlugPluginPtrVector GetAllPlugins() const;
419 
420  /// Returns a plugin with the specified library name. Note that additional
421  /// plugins may be registered during program runtime.
422  /// \sa \ref Plug_Discovery
423  PLUG_API
424  PlugPluginPtr GetPluginWithName(const std::string& name) const;
425 
426  /// Looks for a string associated with \a type and \a key and returns it, or
427  /// an empty string if \a type or \a key are not found.
428  PLUG_API
430  const std::string &key) const;
431 
432  /// Looks for a JsValue associated with \a type and \a key and returns it,
433  /// or a null JsValue if \a type or \a key are not found.
434  PLUG_API
436  const std::string &key) const;
437 
438 private:
439  // Private ctor and dtor since this is a constructed as a singleton.
440  PLUG_LOCAL
441  PlugRegistry();
442 
443  // Registers all plug-ins discovered in any of \a pathsToPlugInfo
444  // but does not send a notice. The priority order of paths is honored if
445  // pathsAreOrdered.
446  PLUG_LOCAL
447  PlugPluginPtrVector
448  _RegisterPlugins(const std::vector<std::string>& pathsToPlugInfo,
449  bool pathsAreOrdered);
450 
451  template <class ConcurrentVector>
452  PLUG_LOCAL
453  void _RegisterPlugin(const Plug_RegistrationMetadata&,
454  ConcurrentVector *newPlugins);
455  PLUG_LOCAL
456  bool _InsertRegisteredPluginPath(const std::string &path);
457 
458  friend class TfSingleton< PlugRegistry >;
459  friend class PlugPlugin; // For _RegisterPlugins().
460 
461 private:
462  TfHashSet<std::string, TfHash> _registeredPluginPaths;
463 
464  std::mutex _mutex;
465 };
466 
468 
470 
471 #endif // PXR_BASE_PLUG_REGISTRY_H
PLUG_API JsValue GetDataFromPluginMetaData(TfType type, const std::string &key) const
PlugRegistry This
Definition: registry.h:323
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
PLUG_API PlugPluginPtrVector GetAllPlugins() const
**But if you need a result
Definition: thread.h:622
static PLUG_API std::vector< TfType > GetDirectlyDerivedTypes(TfType base)
PLUG_API PlugPluginPtrVector RegisterPlugins(const std::string &pathToPlugInfo)
PXR_NAMESPACE_OPEN_SCOPE TF_DECLARE_WEAK_PTRS(PlugPlugin)
PLUG_API PlugPluginPtr GetPluginWithName(const std::string &name) const
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
#define PLUG_LOCAL
Definition: api.h:27
Definition: value.h:44
static PLUG_API void GetAllDerivedTypes(TfType base, std::set< TfType > *result)
static TfType FindDerivedTypeByName(std::string const &typeName)
Definition: registry.h:376
GLuint const GLchar * name
Definition: glcorearb.h:786
static PLUG_API TfType FindDerivedTypeByName(TfType base, std::string const &typeName)
GLdouble t
Definition: glad.h:2397
static PLUG_API TfType FindTypeByName(std::string const &typeName)
PLUG_API PlugPluginPtr GetPluginForType(TfType t) const
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
#define PLUG_API
Definition: api.h:23
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Definition: type.h:47
PLUG_API_TEMPLATE_CLASS(TfSingleton< PlugRegistry >)
static void GetAllDerivedTypes(std::set< TfType > *result)
Definition: registry.h:406
static PLUG_API PlugRegistry & GetInstance()
Returns the singleton PlugRegistry instance.
PLUG_API std::string GetStringFromPluginMetaData(TfType type, const std::string &key) const
std::vector< TfType > TypeVector
Definition: registry.h:324