1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::System::ObjectManager;
10## nofilter(TidyAll::Plugin::OTRS::Perl::LayoutObject)
11## nofilter(TidyAll::Plugin::OTRS::Perl::PodSpelling)
12## nofilter(TidyAll::Plugin::OTRS::Perl::Require)
13## nofilter(TidyAll::Plugin::OTRS::Perl::SyntaxCheck)
14
15use strict;
16use warnings;
17
18use Carp ();
19use Scalar::Util qw(weaken);
20
21# use the "standard" modules directly, so that persistent environments
22# like mod_perl and FastCGI pre-load them at startup
23
24use Kernel::Config;
25use Kernel::Output::HTML::Layout;
26use Kernel::System::Auth;
27use Kernel::System::AuthSession;
28use Kernel::System::Cache;
29use Kernel::System::DateTime;
30use Kernel::System::DB;
31use Kernel::System::Encode;
32use Kernel::System::Group;
33use Kernel::System::Log;
34use Kernel::System::Main;
35use Kernel::System::Web::Request;
36use Kernel::System::User;
37
38=head1 NAME
39
40Kernel::System::ObjectManager - Central singleton manager and object instance generator
41
42=head1 SYNOPSIS
43
44    # In top level scripts only!
45    local $Kernel::OM = Kernel::System::ObjectManager->new();
46
47    # Everywhere: get a singleton instance (and create it, if needed).
48    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
49
50    # Remove singleton objects and all their dependencies.
51    $Kernel::OM->ObjectsDiscard(
52        Objects            => ['Kernel::System::Ticket', 'Kernel::System::Queue'],
53    );
54
55=head1 DESCRIPTION
56
57The ObjectManager is the central place to create and access singleton OTRS objects (via C<L</Get()>>)
58as well as create regular (unmanaged) object instances (via C<L</Create()>>).
59
60=head2 How does singleton management work?
61
62It creates objects as late as possible and keeps references to them. Upon destruction the objects
63are destroyed in the correct order, based on their dependencies (see below).
64
65=head2 How to use it?
66
67The ObjectManager must always be provided to OTRS by the top level script like this:
68
69    use Kernel::System::ObjectManager;
70    local $Kernel::OM = Kernel::System::ObjectManager->new(
71        # possible options for module constructors here
72        LogObject {
73            LogPrefix => 'OTRS-MyTestScript',
74        },
75    );
76
77Then in the code any singleton object can be retrieved that the ObjectManager can handle,
78like Kernel::System::DB:
79
80    return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare('SELECT 1');
81
82=head2 Which objects can be loaded?
83
84The ObjectManager can load every object that declares its dependencies like this in the Perl package:
85
86    package Kernel::System::Valid;
87
88    use strict;
89    use warnings;
90
91    our @ObjectDependencies = (
92        'Kernel::System::Cache',
93        'Kernel::System::DB',
94        'Kernel::System::Log',
95    );
96
97The C<@ObjectDependencies> is the list of objects that the current object will depend on. They will
98be destroyed only after this object is destroyed (only for singletons).
99
100If you want to signal that a package can NOT be loaded by the ObjectManager, you can use the
101C<$ObjectManagerDisabled> flag:
102
103    package Kernel::System::MyBaseClass;
104
105    use strict;
106    use warnings;
107
108    our $ObjectManagerDisabled = 1;
109
110There are a few flags available to convey meta data about the packages to the object manager.
111
112To indicate that a certain package can B<only> be loaded as a singleton, you can use the
113C<IsSingleton> flag. Similarly, you can indicate that a certain package can B<only> be
114created as unmanaged instance, and B<not> as a singleton via the C<NonSingleton> flag.
115By default, the ObjectManager will die if a constructor does not return an object.
116To suppress this in the C<L</Create()>> method, you can use the C<AllowConstructorFailure>
117flag (this will not work with C<L</Get()>>).
118
119    package Kernel::System::MyPackage;
120
121    use strict;
122    use warnings;
123
124    our %ObjectManagerFlags = (
125        IsSingleton             => 1,  # default 0
126        NonSingleton            => 0,  # default 0
127        AllowConstructorFailure => 0,  # default 0
128    );
129
130=head1 PUBLIC INTERFACE
131
132=head2 new()
133
134Creates a new instance of Kernel::System::ObjectManager.
135
136This is typically B<only> needed in top level (C<bin/>) scripts! All parts of the OTRS API assume
137the ObjectManager to be present in C<$Kernel::OM> and use it.
138
139Sometimes objects need parameters to be sent to their constructors,
140these can also be passed to the ObjectManager's constructor like in the following example.
141The hash reference will be flattened and passed to the constructor of the object(s).
142
143    local $Kernel::OM = Kernel::System::ObjectManager->new(
144        Kernel::System::Log => {
145            LogPrefix => 'OTRS-MyTestScript',
146        },
147    );
148
149Alternatively, C<L</ObjectParamAdd()>> can be used to set these parameters at runtime (but this
150must happen before the object was created).
151
152If the C<< Debug => 1 >> option is present, destruction of objects
153is checked, and a warning is emitted if objects persist after the
154attempt to destroy them.
155
156=cut
157
158sub new {
159    my ( $Type, %Param ) = @_;
160    my $Self = bless {}, $Type;
161
162    $Self->{Debug} = delete $Param{Debug};
163
164    for my $Parameter ( sort keys %Param ) {
165        $Self->{Param}->{$Parameter} = $Param{$Parameter};
166    }
167
168    # Kernel::System::Encode->new() initializes the environment, so we need to
169    #   already create an instance here to make sure it is always done and done
170    #   at the beginning of things.
171    $Self->Get('Kernel::System::Encode');
172
173    return $Self;
174}
175
176=head2 Get()
177
178Retrieves a singleton object, and if it not yet exists, implicitly creates one for you.
179
180    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
181
182    # On the second call, this returns the same ConfigObject as above.
183    my $ConfigObject2 = $Kernel::OM->Get('Kernel::Config');
184
185=cut
186
187sub Get {    ## no critic
188
189    # No param unpacking for increased performance
190    if ( $_[1] && $_[0]->{Objects}->{ $_[1] } ) {
191        return $_[0]->{Objects}->{ $_[1] };
192    }
193
194    if ( !$_[1] ) {
195        $_[0]->_DieWithError(
196            Error => "Error: Missing parameter (object name)",
197        );
198    }
199
200    return $_[0]->_ObjectBuild( Package => $_[1] );
201}
202
203=head2 Create()
204
205Creates a new object instance. This instance will not be managed by the object manager later on.
206
207    my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
208
209    # On the second call, this creates a new independent instance.
210    my $DateTimeObject2 = $Kernel::OM->Create('Kernel::System::DateTime');
211
212It is also possible to pass in constructor parameters:
213
214    my $DateTimeObject = $Kernel::OM->Create(
215        'Kernel::System::DateTime',
216        ObjectParams => {
217            Param1 => 'Value1',
218        },
219    );
220
221By default, this method will C<die>, if the package cannot be instantiated or the constructor returns undef.
222You can suppress this with C<< Silent => 1 >>, for example to not cause exceptions when trying
223to load modules based on user configuration.
224
225    my $CustomObject = $Kernel::OM->Create(
226        'Kernel::System::CustomObject',
227        Silent => 1,
228    );
229
230=cut
231
232sub Create {
233    my ( $Self, $Package, %Param ) = @_;
234
235    if ( !$Package ) {
236        $Self->_DieWithError(
237            Error => "Error: Missing parameter (object name)",
238        );
239    }
240
241    return $Self->_ObjectBuild(
242        %Param,
243        Package     => $Package,
244        NoSingleton => 1,
245    );
246}
247
248sub _ObjectBuild {
249    my ( $Self, %Param ) = @_;
250
251    my $Package = $Param{Package};
252    eval {
253        my $FileName = $Param{Package} =~ s{::}{/}smxgr;
254        require $FileName . '.pm';
255    };
256    if ($@) {
257        if ( $Param{Silent} ) {
258            return;    # don't throw
259        }
260        $Self->_DieWithError(
261            Error => "$Package could not be loaded: $@",
262        );
263    }
264
265    # Kernel::Config does not declare its dependencies (they would have to be in
266    #   Kernel::Config::Defaults), so assume [] in this case.
267    my $Dependencies = [];
268
269    no strict 'refs';    ## no critic
270    my %ObjectManagerFlags = %{ $Package . '::ObjectManagerFlags' };
271    use strict 'refs';
272
273    if ( $Package ne 'Kernel::Config' ) {
274        no strict 'refs';    ## no critic
275        if ( !exists ${ $Package . '::' }{ObjectDependencies} ) {
276            $Self->_DieWithError( Error => "$Package does not declare its object dependencies!" );
277        }
278        $Dependencies = \@{ $Package . '::ObjectDependencies' };
279
280        if ( ${ $Package . '::ObjectManagerDisabled' } ) {
281            $Self->_DieWithError( Error => "$Package cannot be loaded via ObjectManager!" );
282        }
283
284        if ( $Param{NoSingleton} ) {
285            if ( $ObjectManagerFlags{IsSingleton} ) {
286                $Self->_DieWithError(
287                    Error =>
288                        "$Package cannot be created as a new instance via ObjectManager! Use Get() instead of Create() to fetch the singleton."
289                );
290            }
291        }
292        else {
293            if ( $ObjectManagerFlags{NonSingleton} ) {
294                $Self->_DieWithError(
295                    Error =>
296                        "$Package cannot be loaded as a singleton via ObjectManager! Use Create() instead of Get() to create new instances."
297                );
298            }
299        }
300
301        use strict 'refs';
302    }
303    $Self->{ObjectDependencies}->{$Package} = $Dependencies;
304
305    my $NewObject = $Package->new(
306        %{ $Param{ObjectParams} // $Self->{Param}->{$Package} // {} }
307    );
308
309    if ( !defined $NewObject ) {
310        if ( $Param{Silent} || $ObjectManagerFlags{AllowConstructorFailure} ) {
311            return;    # don't throw
312        }
313        $Self->_DieWithError(
314            Error => "The constructor of $Package returned undef.",
315        );
316    }
317
318    return $NewObject if ( $Param{NoSingleton} );
319
320    $Self->{Objects}->{$Package} = $NewObject;
321
322    return $NewObject;
323}
324
325=head2 ObjectInstanceRegister()
326
327Adds an existing object instance to the ObjectManager so that it can be accessed by other objects.
328
329This should B<only> be used on special circumstances, e. g. in the unit tests to pass C<$Self> to the
330ObjectManager so that it is also available from there as 'Kernel::System::UnitTest'.
331
332    $Kernel::OM->ObjectInstanceRegister(
333        Package      => 'Kernel::System::UnitTest',
334        Object       => $UnitTestObject,
335        Dependencies => [],         # optional, specify OM-managed packages that the object might depend on
336    );
337
338=cut
339
340sub ObjectInstanceRegister {
341    my ( $Self, %Param ) = @_;
342
343    if ( !$Param{Package} || !$Param{Object} ) {
344        $Self->_DieWithError( Error => 'Need Package and Object.' );
345    }
346
347    if ( defined $Self->{Objects}->{ $Param{Package} } ) {
348        $Self->_DieWithError( Error => 'Need $Param{Package} is already registered.' );
349    }
350
351    $Self->{Objects}->{ $Param{Package} }            = $Param{Object};
352    $Self->{ObjectDependencies}->{ $Param{Package} } = $Param{Dependencies} // [];
353
354    return 1;
355}
356
357=head2 ObjectParamAdd()
358
359Adds arguments that will be passed to constructors of classes
360when they are created, in the same format as the C<L<new()>> method
361receives them.
362
363    $Kernel::OM->ObjectParamAdd(
364        'Kernel::System::Ticket' => {
365            Key => 'Value',
366        },
367    );
368
369To remove a key again, send undef as a value:
370
371    $Kernel::OM->ObjectParamAdd(
372        'Kernel::System::Ticket' => {
373            Key => undef,               # this will remove the key from the hash
374        },
375    );
376
377=cut
378
379sub ObjectParamAdd {
380    my ( $Self, %Param ) = @_;
381
382    for my $Package ( sort keys %Param ) {
383        if ( ref( $Param{$Package} ) eq 'HASH' ) {
384            for my $Key ( sort keys %{ $Param{$Package} } ) {
385                if ( defined $Key ) {
386                    $Self->{Param}->{$Package}->{$Key} = $Param{$Package}->{$Key};
387                }
388                else {
389                    delete $Self->{Param}->{$Package}->{$Key};
390                }
391            }
392        }
393        else {
394            $Self->{Param}->{$Package} = $Param{$Package};
395        }
396    }
397    return;
398}
399
400=head2 ObjectEventsHandle()
401
402Execute all queued (C<< Transaction => 1 >>) events for all singleton objects
403that the ObjectManager created before. This can be used to flush the event queue
404before destruction, for example.
405
406    $Kernel::OM->ObjectEventsHandle();
407
408=cut
409
410sub ObjectEventsHandle {
411    my ( $Self, %Param ) = @_;
412
413    my $HasQueuedTransactions;
414    EVENTS:
415    for my $Counter ( 1 .. 10 ) {
416        $HasQueuedTransactions = 0;
417        EVENTHANDLERS:
418        for my $EventHandler ( @{ $Self->{EventHandlers} } ) {
419
420            # since the event handlers are weak references,
421            # they might be undef by now.
422            next EVENTHANDLERS if !defined $EventHandler;
423            if ( $EventHandler->EventHandlerHasQueuedTransactions() ) {
424                $HasQueuedTransactions = 1;
425                $EventHandler->EventHandlerTransaction();
426            }
427        }
428        if ( !$HasQueuedTransactions ) {
429            last EVENTS;
430        }
431    }
432    if ($HasQueuedTransactions) {
433        warn "Unable to handle all pending events in 10 iterations";
434    }
435    delete $Self->{EventHandlers};
436
437    return;
438}
439
440=head2 ObjectsDiscard()
441
442Discards internally stored objects, so that the next access to objects
443creates them newly. If a list of object names is passed, only
444the supplied objects and their recursive dependencies are destroyed.
445If no list of object names is passed, all stored objects are destroyed.
446
447    $Kernel::OM->ObjectsDiscard();
448
449    $Kernel::OM->ObjectsDiscard(
450        Objects            => ['Kernel::System::Ticket', 'Kernel::System::Queue'],
451
452        # optional
453        # forces the packages to be reloaded from the file system
454        # sometimes necessary with mod_perl when running CodeUpgrade during a package upgrade
455        # if no list of object names is passed, all stored objects are destroyed
456        # and forced to be reloaded
457        ForcePackageReload => 1,
458    );
459
460Mostly used for tests that rely on fresh objects, or to avoid large
461memory consumption in long-running processes.
462
463Note that if you pass a list of objects to be destroyed, they are destroyed
464in in the order they were passed; otherwise they are destroyed in reverse
465dependency order.
466
467=cut
468
469sub ObjectsDiscard {
470    my ( $Self, %Param ) = @_;
471
472    # fire outstanding events before destroying anything
473    $Self->ObjectEventsHandle();
474
475    # destroy objects before their dependencies are destroyed
476
477    # first step: get the dependencies into a single hash,
478    # so that the topological sorting goes faster
479    my %ReverseDependencies;
480    my @AllObjects;
481    for my $Object ( sort keys %{ $Self->{Objects} } ) {
482        my $Dependencies = $Self->{ObjectDependencies}->{$Object};
483
484        for my $Dependency (@$Dependencies) {
485
486            # undef happens to be the value that uses the least amount
487            # of memory in Perl, and we are only interested in the keys
488            $ReverseDependencies{$Dependency}->{$Object} = undef;
489        }
490        push @AllObjects, $Object;
491    }
492
493    # During an OTRS package upgrade the packagesetup code module has just
494    # recently been copied to it's location in the file system.
495    # In a persistent Perl environment an old version of the module might still be loaded,
496    # as watchdogs like Apache2::Reload haven't had a chance to reload it.
497    # So we need to make sure that the new version is being loaded.
498    # Kernel::System::Main::Require() checks the relative file path, so we need to remove that from %INC.
499    # This is only needed in persistent Perl environment, but does no harm in a CGI environment.
500    if ( $Param{ForcePackageReload} ) {
501
502        my @Objects;
503        if ( $Param{Objects} && @{ $Param{Objects} } ) {
504            @Objects = @{ $Param{Objects} };
505        }
506        else {
507            @Objects = @AllObjects;
508        }
509
510        for my $Object (@Objects) {
511
512            # convert :: to / in order to build a file system path name
513            my $ObjectPath = $Object;
514            $ObjectPath =~ s/::/\//g;
515
516            # attach .pm as file extension
517            $ObjectPath .= '.pm';
518
519            # delete from global %INC hash
520            delete $INC{$ObjectPath};
521        }
522    }
523
524    # second step: post-order recursive traversal
525    my %Seen;
526    my @OrderedObjects;
527    my $Traverser;
528    $Traverser = sub {
529        my ($Object) = @_;
530        return if $Seen{$Object}++;
531        for my $ReverseDependency ( sort keys %{ $ReverseDependencies{$Object} } ) {
532            $Traverser->($ReverseDependency);
533        }
534        push @OrderedObjects, $Object;
535    };
536
537    if ( $Param{Objects} ) {
538        for my $Object ( @{ $Param{Objects} } ) {
539            $Traverser->($Object);
540        }
541    }
542    else {
543        for my $Object (@AllObjects) {
544            $Traverser->($Object);
545        }
546    }
547    undef $Traverser;
548
549    # third step: destruction
550    if ( $Self->{Debug} ) {
551
552        # If there are undeclared dependencies between objects, destruction
553        # might not work in the order that we calculated, but might still work
554        # out in the end.
555        my %DestructionFailed;
556        for my $Object (@OrderedObjects) {
557            my $Checker = $Self->{Objects}->{$Object};
558            weaken($Checker);
559            delete $Self->{Objects}->{$Object};
560
561            if ( defined $Checker ) {
562                $DestructionFailed{$Object} = $Checker;
563                weaken( $DestructionFailed{$Object} );
564            }
565        }
566        for my $Object ( sort keys %DestructionFailed ) {
567            if ( defined $DestructionFailed{$Object} ) {
568                warn "DESTRUCTION OF $Object FAILED!\n";
569                if ( eval { require Devel::Cycle; 1 } ) {
570                    Devel::Cycle::find_cycle( $DestructionFailed{$Object} );
571                }
572                else {
573                    warn "To get more debugging information, please install Devel::Cycle.";
574                }
575            }
576        }
577    }
578    else {
579        for my $Object (@OrderedObjects) {
580            delete $Self->{Objects}{$Object};
581        }
582    }
583
584    # if an object requests an already destroyed object
585    # in its DESTROY method, we might hold it again, and must try again
586    # (but not infinitely)
587    if ( !$Param{Objects} && keys %{ $Self->{Objects} } ) {
588        if ( $Self->{DestroyAttempts} && $Self->{DestroyAttempts} > 3 ) {
589            $Self->_DieWithError( Error => "Loop while destroying objects!" );
590        }
591
592        $Self->{DestroyAttempts}++;
593        $Self->ObjectsDiscard();
594        $Self->{DestroyAttempts}--;
595    }
596
597    return 1;
598}
599
600=head2 ObjectRegisterEventHandler()
601
602Registers an object that can handle asynchronous events.
603
604    $Kernel::OM->ObjectRegisterEventHandler(
605        EventHandler => $EventHandlerObject,
606    );
607
608The C<EventHandler> object should inherit from L<Kernel::System::EventHandler>.
609The object manager will call that object's C<EventHandlerHasQueuedTransactions>
610method, and if that returns a true value, calls its C<EventHandlerTransaction> method.
611
612=cut
613
614sub ObjectRegisterEventHandler {
615    my ( $Self, %Param ) = @_;
616    if ( !$Param{EventHandler} ) {
617        die "Missing parameter EventHandler";
618    }
619    push @{ $Self->{EventHandlers} }, $Param{EventHandler};
620    weaken( $Self->{EventHandlers}[-1] );
621    return 1;
622}
623
624sub _DieWithError {
625    my ( $Self, %Param ) = @_;
626
627    if ( $Self->{Objects}->{'Kernel::System::Log'} ) {
628        $Self->{Objects}->{'Kernel::System::Log'}->Log(
629            Priority => 'Error',
630            Message  => $Param{Error},
631        );
632    }
633
634    Carp::croak $Param{Error};    # This will die().
635}
636
637sub DESTROY {
638    my ($Self) = @_;
639
640    # Make sure $Kernel::OM is still available in the destructor
641    local $Kernel::OM = $Self;
642    $Self->ObjectsDiscard();
643
644    return;
645}
646
647=head1 TERMS AND CONDITIONS
648
649This software is part of the OTRS project (L<https://otrs.org/>).
650
651This software comes with ABSOLUTELY NO WARRANTY. For details, see
652the enclosed file COPYING for license information (GPL). If you
653did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
654
655=cut
656
6571;
658