/
system.py
7361 lines (5805 loc) · 275 KB
/
system.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Hive Colony Framework
# Copyright (c) 2008-2019 Hive Solutions Lda.
#
# This file is part of Hive Colony Framework
#
# Hive Colony Framework is free software: you can redistribute it and/or modify
# it under the terms of the Apache License as published by the Apache
# Foundation, either version 2.0 of the License, or (at your option) any
# later version.
#
# Hive Colony Framework is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Apache License for more details.
#
# You should have received a copy of the Apache License along with
# Hive Colony Framework If not, see <http://www.apache.org/licenses/>.
__author__ = "João Magalhães <joamag@hive.pt>"
""" The author(s) of the module """
__version__ = "1.3.28"
""" The version of the module """
__revision__ = "$LastChangedRevision$"
""" The revision number of the module """
__date__ = "$LastChangedDate$"
""" The last change date of the module """
__copyright__ = "Copyright (c) 2008-2019 Hive Solutions Lda."
""" The copyright for the module """
__license__ = "Apache License, Version 2.0"
""" The license for the module """
import os
import re
import sys
import copy
import stat
import time
import signal
import inspect
import unittest
import tempfile
import threading
import traceback
import subprocess
import logging.handlers
import colony.libs
from . import util
from . import legacy
from . import config
from . import loggers
from . import exceptions
from . import information
GLOBAL_CONFIG = config.GLOBAL_CONFIG
""" The global static configuration of the manager that
is going to be used for some of the operations """
CPYTHON_ENVIRONMENT = util.CPYTHON_ENVIRONMENT
""" CPython environment value """
JYTHON_ENVIRONMENT = util.JYTHON_ENVIRONMENT
""" Jython environment value """
IRON_PYTHON_ENVIRONMENT = util.IRON_PYTHON_ENVIRONMENT
""" IronPython environment value """
DEFAULT_LOGGER = "default_messages"
""" The default logger name """
DEFAULT_LOGGING_LEVEL = logging.INFO
""" The default logging level to be used as the minimal
logging level to all the default (verbose) loggers """
DEFAULT_LOGGING_FORMAT = "%(asctime)s [%(levelname)s] %(message)s"
""" The default logging format """
DEFAULT_LOGGING_FILE_NAME_PREFIX = "colony"
""" The default logging file name prefix """
DEFAULT_LOGGING_FILE_NAME_SEPARATOR = "_"
""" The default logging file name separator """
DEFAULT_LOGGING_FILE_NAME_EXTENSION = ".log"
""" The default logging file name extension """
DEFAULT_LOGGING_ERR_FILE_NAME_EXTENSION = ".err"
""" The default logging file name extension
for the error type of file logging """
DEFAULT_LOGGING_FILE_MODE = "a"
""" The default logging file mode """
DEFAULT_LOGGING_FILE_SIZE = 10485760
""" The default logging file size """
DEFAULT_LOGGING_FILE_BACKUP_COUNT = 5
""" The default logging file backup count """
DEFAULT_CONTAINERS_PATH = "containers"
""" The default containers path """
DEFAULT_LIBRARIES_PATH = "libraries"
""" The default libraries path """
DEFAULT_TEMPORARY_PATH = "tmp"
""" The default temporary path """
DEFAULT_VARIABLE_PATH = "var"
""" The default variable path """
DEFAULT_PLUGIN_PATH = "plugins"
""" The default plugin path """
DEFAULT_CONFIGURATION_PATH = "meta"
""" The default configuration path """
DEFAULT_PLUGIN_PATHS_FILE_PATH = "config/general/plugins.pth"
""" The default plugin paths file path """
DEFAULT_WORKSPACE_PATH = "~/.colony_workspace"
""" The default workspace path """
DEFAULT_UNLOAD_SYSTEM_TIMEOUT = 600.0
""" The default unload system timeout """
EAGER_LOADING_TYPE = "eager_loading"
""" The eager loading plugin loading type """
LAZY_LOADING_TYPE = "lazy_loading"
""" The lazy loading plugin loading type """
PLUGIN_MANAGER_EXTENSION_TYPE = "plugin_manager_extension"
""" The plugin manager type """
MAIN_TYPE = "main"
""" The main plugin type """
STARTUP_TYPE = "startup"
""" The startup plugin type """
THREAD_TYPE = "thread"
""" The thread plugin type """
FULL_LOAD_TYPE = "full_load"
""" The full load plugin loading type """
DEPENDENCY_TYPE = "dependency"
""" The dependency plugin loading/unloading type """
ALLOWED_TYPE = "allowed"
""" The allowed plugin loading/unloading type """
SINGLETON_DIFFUSION_SCOPE = 1
""" The singleton diffusion scope """
SAME_DIFFUSION_SCOPE = 2
""" The same diffusion scope """
NEW_DIFFUSION_SCOPE = 3
""" The new diffusion scope """
FILE_REMOVED_TYPE = "file_removed"
""" The file removed plugin loading/unloading type """
SPECIAL_VALUE_REGEX_VALUE = "%(?P<command>[a-zA-Z0-0_]*)(:(?P<arguments>[a-zA-Z0-9_.,]*))?%"
""" The special value regex value """
SPECIAL_VALUE_REGEX = re.compile(SPECIAL_VALUE_REGEX_VALUE)
""" The special value regex """
ALIAS_MAP = dict(
devel = "development",
prod = "production",
runtime = "production"
)
""" The map that is going to be used for the final resolution
of the layout/run modes, this is used so that shorter names
may be used for this modes (simplified execution) """
class System(object):
"""
The base system class from which all the back end
plugin system classes may inherit to obtain some
generalized behavior on the plugin access.
"""
plugin = None
""" The reference to the plugin that "owns" this
system object, this may be used to reference the
top level manager functions """
def __init__(self, plugin):
"""
Constructor of the class, received the "owner"
plugin as the first argument to be stored for
latter usage.
:type plugin: Plugin
:param plugin: The owner plugin for the system
object to be created.
"""
self.plugin = plugin
def get_manager(self):
"""
Retrieves the plugin manager reference associated
with the current system, this method call depends
on the definition of the owner plugin.
:rtype: PluginManager
:return: The plugin manager instance associated with
the current execution context.
"""
return self.plugin.manager
def debug(self, *args, **kwargs):
return self.plugin.debug(*args, **kwargs)
def info(self, *args, **kwargs):
return self.plugin.info(*args, **kwargs)
def warning(self, *args, **kwargs):
return self.plugin.warning(*args, **kwargs)
def error(self, *args, **kwargs):
return self.plugin.error(*args, **kwargs)
def critical(self, *args, **kwargs):
return self.plugin.critical(*args, **kwargs)
class Plugin(object):
"""
The abstract plugin class.
Contains most of the basic utility function and handlers
used during the plugin file cycle.
All the concrete plugin implementation should inherit from
this class so that they become compatible with the base
colony specification for python.
"""
id = None
""" The id of the plugin, this is considered to be the
primary identifier of the plugin and should be unique """
name = None
""" The name of the plugin as a more relaxed and verbose
way of presenting the plugin """
description = None
""" The description of the plugin """
version = None
""" The version of the plugin """
author = None
""" The author of the plugin """
loading_type = EAGER_LOADING_TYPE
""" The type of loading of the plugin """
platforms = []
""" The compatible platforms of the plugin """
attributes = {}
""" The attributes of the plugin """
capabilities = []
""" The capabilities of the plugin """
capabilities_allowed = []
""" The capabilities allowed by the plugin """
dependencies = []
""" The dependencies of the plugin """
events_fired = []
""" The events fired by the plugin """
events_handled = []
""" The events that the plugin can handle """
main_modules = []
""" The main modules of the plugin, this value
should reference the complete set of prefix values
that should be used as reference for module operation
for instance this value is going to be used as the
reference for the reloading of modules for the
autoloading operations """
valid = True
""" The valid flag of the plugin """
logger = None
""" The reference to the logger object that is
going to be used by the plugin in the logging
operation, this may come from an external source """
timestamp = None
""" The timestamp that stores the load time
of the last load operation, this value is not
set in case the plugin is not loaded """
dependencies_loaded = []
""" The list of dependency plugins loaded """
allowed_loaded_capability = []
""" The list of allowed plugins loaded with capability """
event_plugins_fired_loaded_map = {}
""" The map with the plugin associated with
the name of the event fired """
event_plugins_registered_loaded_map = {}
""" The map with the plugin associated with
the name of the event registered """
event_plugin_manager_registered_loaded_list = []
""" The list with all the events registered
in the plugin manager """
configuration_map = {}
""" The configuration of the plugin """
loaded = False
""" The loading flag """
lazy_loaded = False
""" The lazy loading flag """
error_state = False
""" The error state flag """
exception = None
""" The exception associated with the error state """
ready_semaphore = None
""" The ready semaphore """
ready_semaphore_lock = None
""" The ready semaphore lock """
ready_semaphore_release_count = 0
""" The ready semaphore release count """
original_id = None
""" The original id of the plugin """
diffusion_scope_id = None
""" The diffusion scope id of the plugin """
manager = None
""" The parent plugin manager """
def __init__(self, manager = None):
"""
Constructor of the class.
:type manager: PluginManager
:param manager: The plugin manager of the system.
"""
self.original_id = self.id
self.manager = manager
self.ready_semaphore = threading.Semaphore(0)
self.ready_semaphore_lock = threading.Lock()
self.ready_semaphore_release_count = 0
self.logger = logging.getLogger(DEFAULT_LOGGER)
self.dependencies_loaded = []
self.allowed_loaded_capability = []
self.event_plugins_fired_loaded_map = {}
self.event_plugins_registered_loaded_map = {}
self.event_plugin_manager_registered_loaded_list = []
self.configuration_map = {}
self.loaded = False
self.lazy_loaded = False
self.error_state = False
def __repr__(self):
"""
Returns the default representation of the class.
:rtype: String
:return: The default representation of the class.
"""
return "<%s, %s, %s, %r>" % (
self.__class__.__name__,
self.name,
self.version,
self.capabilities,
)
def load_plugin(self):
"""
Method called at the beginning of the plugin loading process.
"""
# iterates over the complete set of allowed capabilities to be able
# to creates the required structures for the access to the loaded
# allowed plugins, note that they have not been loaded yet into the
# current plugin, so we can change the internal values of structures
for capability in self.capabilities_allowed:
setattr(self, capability, {})
setattr(self, capability + "_plugins", [])
# registers all the plugin manager events
self.register_all_plugin_manager_events()
# sets the values of a series of flags that control the state of the
# current plugin, these values may be used in flow control
self.loaded = True
self.lazy_loaded = False
self.error_state = False
# resets the (load) timestamp value to the current
# timestamp, with this value it will be possible to
# calculate the uptime for the plugin
self.timestamp = time.time()
# generates the load plugin event
self.manager.generate_event("plugin_manager.plugin.load_plugin", [self.id, self.version, self])
# prints an info message
self.info("Loading plugin '%s' v%s" % (self.name, self.version))
def lazy_load_plugin(self):
"""
Method called at the beginning of the lazy plugin loading process.
"""
# registers all the plugin manager events
self.register_all_plugin_manager_events()
# sets the values of a series of flags that control the state of the
# current plugin, these values may be used in flow control
self.loaded = True
self.lazy_loaded = True
self.error_state = False
# generates the lazy load plugin event
self.manager.generate_event("plugin_manager.plugin.lazy_load_plugin", [self.id, self.version, self])
# prints a debug message
self.debug("Lazy loading plugin '%s' v%s" % (self.name, self.version))
def end_load_plugin(self):
"""
Method called at the end of the plugin loading process.
"""
# generates the end load plugin event
self.manager.generate_event("plugin_manager.plugin.end_load_plugin", [self.id, self.version, self])
self.debug("Loading process for plugin '%s' v%s completed" % (self.name, self.version))
def unload_plugin(self):
"""
Method called at the beginning of the plugin unloading process.
"""
# unregisters all the plugin manager events
self.unregister_all_plugin_manager_events()
self.unregister_all_for_plugin()
self.loaded = False
# sets the error state as false
self.error_state = False
# restores the timestamp value to the original (unset)
# to avoid erroneous calculation of uptime values
self.timestamp = None
# resets the dependencies loaded (no dependencies
# are loaded in the plugin at the end of the unload)
self.dependencies_loaded = []
# resets the allowed loaded capability (no allowed
# are loaded in the plugin at the end of the unload)
self.allowed_loaded_capability = []
# generates the load plugin event
self.manager.generate_event("plugin_manager.plugin.unload_plugin", [self.id, self.version, self])
# prints an info message
self.info("Unloading plugin '%s' v%s" % (self.name, self.version))
def end_unload_plugin(self):
"""
Method called at the end of the plugin unloading process.
"""
# sets the error state as false
self.error_state = False
# generates the load plugin event
self.manager.generate_event("plugin_manager.plugin.end_unload_plugin", [self.id, self.version, self])
# prints an info message
self.info("Unloading process for plugin '%s' v%s completed" % (self.name, self.version))
def load_allowed(self, plugin, capability):
"""
Method called at the loading of an allowed plugin.
:type plugin: Plugin
:param plugin: The allowed plugin that is being loaded.
:type capability: String
:param capability: Capability for which the plugin is being injected.
"""
# creates the plugin capability tuple that is going to represent
# the relation between the current plugin and the allowed one
plugin_capability_tuple = (
plugin,
capability
)
# in case the plugin capability tuple already exists in
# the allowed loaded capability list, an exception must
# be raised indicating the problem (assertion)
if plugin_capability_tuple in self.allowed_loaded_capability:
raise exceptions.PluginSystemException(
"invalid plugin allowed loading (duplicate) '%s' v%s in '%s' v%s" %
(plugin.name, plugin.version, self.name, self.version)
)
# in case the current plugin does not have the capability plugins
# definition set creates a new map for it and then registers the
# newly allowed plugin in the map (for latter usage)
if not hasattr(self, capability): setattr(self, capability, {})
allowed = getattr(self, capability)
allowed[plugin.short_name] = plugin
# verifies if the current plugin already has the plugins list for
# the current capability created and if that's not the case creates
# a new list and then appends the current allowed plugin to the list
if not hasattr(self, capability + "_plugins"):
setattr(self, capability + "_plugins", [])
allowed_list = getattr(self, capability + "_plugins")
allowed_list.append(plugin)
# adds the plugin capability tuple to the allowed loaded capability
# and registers for all handled events
self.allowed_loaded_capability.append(plugin_capability_tuple)
self.register_all_handled_events_plugin(plugin)
# prints a debug message about the loading of the plugin inside
# the current plugin (for diagnostic purposes)
self.debug(
"Loading plugin '%s' v%s in '%s' v%s" %
(plugin.name, plugin.version, self.name, self.version)
)
def unload_allowed(self, plugin, capability):
"""
Method called at the unloading of an allowed plugin.
:type plugin: Plugin
:param plugin: The allowed plugin that is being unloaded.
:type capability: String
:param capability: Capability for which the plugin is being injected.
"""
# creates the plugin capability tuple
plugin_capability_tuple = (
plugin,
capability
)
# in case the plugin capability tuple does not exist in
# the allowed loaded capability list, this is an error
# and an exception must be raised indicating it
if not plugin_capability_tuple in self.allowed_loaded_capability:
raise exceptions.PluginSystemException(
"invalid plugin allowed unloading (not existent) '%s' v%s in '%s' v%s" %
(plugin.name, plugin.version, self.name, self.version)
)
# retrieves the map of allowed loaded plugin for the current
# plugin and removes the reference to the plugin to be unloaded
# from that map as it is no longer allowed in the current plugin
allowed = getattr(self, capability)
del allowed[plugin.short_name]
# retrieves the list of allowed plugins for the current capability
# that is currently registered and then removes the current plugin
# from it as it's currently being unloaded (as expected)
allowed_list = getattr(self, capability + "_plugins")
allowed_list.remove(plugin)
# removes the plugin capability tuple from the allowed loaded capability
# and then unregisters for all handled events of the plugin to be unloaded
self.allowed_loaded_capability.remove(plugin_capability_tuple)
self.unregister_all_handled_events_plugin(plugin)
# prints an info message about the unloading of the plugin
# so that the developer is notified about the operation
self.info(
"Unloading plugin '%s' v%s in '%s' v%s" %
(plugin.name, plugin.version, self.name, self.version)
)
def dependency_injected(self, plugin):
"""
Method called at the injection of a plugin dependency.
Should change the current plugin instance so that it
is able to recognizes the newly injected plugin instance.
:type plugin: Plugin
:param plugin: The dependency plugin to be injected.
"""
# adds the dependency that was injected into the list of
# loaded dependencies and then "injects" the plugin into
# the plugin where it is being loaded, then loads a message
# about the injection of the dependency
self.dependencies_loaded.append(plugin)
setattr(self, plugin.short_name + "_plugin", plugin)
self.debug(
"Plugin dependency '%s' v%s injected in '%s' v%s" %
(plugin.name, plugin.version, self.name, self.version)
)
def init_complete(self):
"""
Method called at the end of the plugin manager initialization.
"""
self.debug("Plugin '%s' v%s notified about the end of the plugin manager init process" % (self.name, self.version))
def register_all_handled_events_plugin(self, plugin):
"""
Registers all the allowed events from a given plugin in self.
:type plugin: Plugin
:param plugin: The plugin containing the events to be registered.
"""
event_names_handled = [event_name for event_name in plugin.events_fired if is_event_or_super_event_in_list(event_name, self.events_handled)]
for event_name_handled in event_names_handled:
self.register_for_plugin_event(plugin, event_name_handled)
def unregister_all_handled_events_plugin(self, plugin):
"""
Unregisters all the allowed events from a given plugin in self.
:type plugin: Plugin
:param plugin: The plugin containing the events to be unregistered.
"""
for event_name in self.event_plugins_registered_loaded_map:
if plugin in self.event_plugins_registered_loaded_map[event_name]:
self.unregister_for_plugin_event(plugin, event_name)
def register_all_plugin_manager_events(self):
"""
Registers all the plugin manager events in self.
"""
event_names_handled = [event_name for event_name in self.events_handled if is_event_or_sub_event("plugin_manager", event_name)]
for event_name_handled in event_names_handled:
self.register_for_plugin_manager_event(event_name_handled)
def unregister_all_plugin_manager_events(self):
"""
Unregisters all the plugin manager events in self.
"""
event_plugin_manager_registered_loaded_list = copy.copy(self.event_plugin_manager_registered_loaded_list)
for event_name in event_plugin_manager_registered_loaded_list:
self.unregister_for_plugin_manager_event(event_name)
def register_for_plugin_event(self, plugin, event_name):
"""
Registers a given event from a given plugin in self.
:type plugin: Plugin
:param plugin: The plugin containing the event to be registered.
:type event_name: String
:param event_name: The name of the event to be registered.
"""
# in case the plugin is not loaded or lazy loaded
if not plugin.is_loaded_or_lazy_loaded():
return
# registers the plugin event in the plugin containing the event
plugin.register_plugin_event(self, event_name)
# in case it's the first plugin to be registered for the given event
if not event_name in self.event_plugins_registered_loaded_map:
self.event_plugins_registered_loaded_map[event_name] = []
# appends the plugin containing the event to be registered to the plugin events map
self.event_plugins_registered_loaded_map[event_name].append(plugin)
def unregister_for_plugin_event(self, plugin, event_name):
"""
Unregisters a given event from a given plugin in self.
:type plugin: Plugin
:param plugin: The plugin containing the event to be unregistered.
:type event_name: String
:param event_name: The name of the event to be unregistered.
"""
# in case the plugin is not loaded or lazy loaded
if not plugin.is_loaded_or_lazy_loaded():
return
# unregisters the plugin event in the plugin containing the event
plugin.unregister_plugin_event(self, event_name)
if event_name in self.event_plugins_registered_loaded_map:
if plugin in self.event_plugins_registered_loaded_map[event_name]:
self.event_plugins_registered_loaded_map[event_name].remove(plugin)
def register_for_plugin_manager_event(self, event_name):
"""
Registers a given plugin manager event in self.
:type event_neme: String
:param event_name: The name of the event to be registered.
"""
# retrieves the plugin manager
plugin_manager = self.manager
# registers the plugin event in the plugin manager containing the event
plugin_manager.register_plugin_manager_event(self, event_name)
# appends the plugin manager containing the event to be registered to the plugin manager events map
self.event_plugin_manager_registered_loaded_list.append(event_name)
def unregister_for_plugin_manager_event(self, event_name):
"""
Unregisters a given plugin manager event in self.
:type event_name: String
:param event_name: The name of the event to be unregistered.
"""
# retrieves the plugin manager
plugin_manager = self.manager
# unregisters the plugin event in the plugin manager containing the event
plugin_manager.unregister_plugin_manager_event(self, event_name)
if event_name in self.event_plugin_manager_registered_loaded_list:
self.event_plugin_manager_registered_loaded_list.remove(event_name)
def unregister_all_for_plugin_event(self, event_name):
"""
Unregisters all the handlers for the event with the given name.
:type event_name: String
:param event_name: The name of the event to be unregistered.
"""
if event_name in self.event_plugins_registered_loaded_map:
for plugin in self.event_plugins_registered_loaded_map[event_name]:
if not plugin.is_loaded_or_lazy_loaded(): continue
self.unregister_for_plugin_event(plugin, event_name)
def unregister_all_for_plugin(self):
"""
Unregisters all the event handlers for the events of self.
"""
for event_name in self.event_plugins_registered_loaded_map:
self.unregister_all_for_plugin_event(event_name)
def register_plugin_event(self, plugin, event_name):
"""
Registers a given event in the given plugin.
:type plugin: Plugin
:param plugin: The plugin containing the handler to the event.
:type event_name: String
:param event_name: The name of the event to be registered.
"""
if not event_name in self.event_plugins_fired_loaded_map:
self.event_plugins_fired_loaded_map[event_name] = []
if plugin in self.event_plugins_fired_loaded_map[event_name]: return
self.event_plugins_fired_loaded_map[event_name].append(plugin)
self.debug(
"Registering event '%s' from '%s' v%s in '%s' v%s" %
(event_name, plugin.name, plugin.version, self.name, self.version)
)
def unregister_plugin_event(self, plugin, event_name):
"""
Unregisters a given event in the given plugin.
:type plugin: Plugin
:param plugin: The plugin containing the handler to the event.
:type event_name: String
:param event_name: The name of the event to be unregistered.
"""
if not event_name in self.event_plugins_fired_loaded_map: return
if not plugin in self.event_plugins_fired_loaded_map[event_name]: return
self.event_plugins_fired_loaded_map[event_name].remove(plugin)
self.debug(
"Unregistering event '%s' from '%s' v%s in '%s' v%s" %
(event_name, plugin.name, plugin.version, self.name, self.version)
)
def notify_handlers(self, event_name, event_args):
"""
Notifies all the handlers for the event with the given name
with the give arguments.
:type event_name: String
:param event_name: The name of the event to be notified.
:type event_args: List
:param event_args: The arguments to be passed to the handler.
"""
# the names of the events fired by self
event_names_list = legacy.keys(self.event_plugins_fired_loaded_map)
# retrieves all the events and super events that match the generated event
events_or_super_events_list = get_all_events_or_super_events_in_list(event_name, event_names_list)
# iterates over all the events and super events for notification
for event_or_super_event in events_or_super_events_list:
if not event_or_super_event in self.event_plugins_fired_loaded_map: continue
# iterates over all the plugins registered for notification
for event_plugin_loaded in self.event_plugins_fired_loaded_map[event_or_super_event]:
# prints a debug message
self.debug(
"Notifying '%s' v%s about event '%s' generated in '%s' v%s" %
(
event_plugin_loaded.name,
event_plugin_loaded.version,
event_name,
self.name,
self.version
)
)
# calls the event handler for the event name with
# the given event arguments
event_plugin_loaded.event_handler(event_name, *event_args)
def generate_event(self, event_name, event_args):
"""
Generates an event and starts the process of handler notification.
:type event_name: String
:param event_name: The name of the event to be notified.
:type event_args: List
:param event_args: The arguments to be passed to the handler.
"""
if not is_event_or_super_event_in_list(event_name, self.events_fired):
return
# prints a debug message
self.debug("Event '%s' generated in '%s' v%s" % (event_name, self.name, self.version))
# notifies the event handlers
self.notify_handlers(event_name, event_args)
def event_handler(self, event_name, *event_args):
"""
The top level event handling method.
:type event_name: String
:param event_name: The name of the event triggered.
:type event_args: List
:param event_args: The arguments for the handler.
"""
# prints a debug message
self.debug("Event '%s' caught in '%s' v%s" % (event_name, self.name, self.version))
def reload_main_modules(self):
"""
Reloads the plugin main modules in the interpreter.
The strategy to be executed implies that the modules
currently loaded in the system that are prefixed with
the names defined in the main modules should be reloaded
or in case an error occurs in the import removed from
the currently loading memory for modules.
This is a dangerous operation and care should be taken
to avoid any system state corruption.
"""
# prints an info message about the reloading of the main modules
# of the plugins that is going to be performed
self.info("Reloading main modules in '%s' v%s" % (self.name, self.version))
# creates the list that will hold the complete set of modules that
# are considered valid for the reload of modules operation
valids = []
# iterates over all the main modules in order to reloaded them
# under the current environment, required for new updating
for main_module in self.main_modules:
# gathers the complete set of loaded modules that are prefixed
# by the name defined as the current main module in iteration
# and then extends the complete set of valid modules with them
# also adds the main module that is defined with such name
prefix = main_module + "."
modules = [module for module in sys.modules if module.startswith(prefix)]
valids.extend(modules)
valids.append(main_module)
# creates the simple sorter lambda function that will sort the list
# of valid modules for reloading and runs the sorting operation so that
# the final list of valid modules for reload is defined from the larger
# (longest module names) to the shortest as required for correct loading
sorter = lambda item: len(item)
valids = list(set(valids))
valids.sort(key = sorter, reverse = True)
# iterates over the complete set of valid modules for reloading and runs
# and tries to run the reloading logic for each of them, in case it fails
# with an import error (assumes cycle error) the module is removed and it
# should be reloaded during the next import operation
for valid in valids:
module = sys.modules[valid]
if not module: continue
try: legacy.reload(module)
except ImportError: del sys.modules[valid]
def get_configuration_property(self, property_name):
"""
Returns the configuration property for the given property name.
:type property_name: String
:param property_name: The property name to retrieve the property.
:rtype: Object
:return: The configuration property for the given property name.
"""
return self.configuration_map.get(property_name, None)
def set_configuration_property(self, property_name, property):
"""
Sets the configuration property for the given property name.
:type property_name: String
:param property_name: The property name to set the property.
:type property: String
:param property: The property name to set.
"""
self.info(
"Setting configuration property '%s' in '%s' v%s" %
(property_name, self.name, self.version)
)
self.configuration_map[property_name] = property
def unset_configuration_property(self, property_name):
"""
Unsets the configuration property for the given property name.
:type property_name: String
:param property_name: The property name to unset the property.
"""
self.info(
"Unsetting configuration property '%s' from '%s' v%s" %
(property_name, self.name, self.version)
)
del self.configuration_map[property_name]
def ensure(self):
"""
Ensures that the current plugin instance is loaded,
loading it if required.