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