# -- # Copyright (C) 2001-2019 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::EventHandler; ## nofilter(TidyAll::Plugin::OTRS::Perl::Pod::FunctionPod) use strict; use warnings; use Kernel::System::VariableCheck qw(IsArrayRefWithData); our $ObjectManagerDisabled = 1; =head1 NAME Kernel::System::EventHandler - event handler interface =head1 DESCRIPTION Inherit from this class if you want to use events there. use parent qw(Kernel::System::EventHandler); In your class, have to call L first. Then, to register events as they occur, use the L method. It will call the event handler modules which are registered for the given event, or queue them for later execution (so-called 'Transaction' events). In the destructor, you should add a call to L to make sure that also C events will be executed correctly. This is only necessary if you use C events in your class. =head1 PUBLIC INTERFACE =head2 EventHandlerInit() Call this to initialize the event handling mechanisms to work correctly with your object. $Self->EventHandlerInit( # name of configured event modules Config => 'Example::EventModule', ); Example 1: $Self->EventHandlerInit( Config => 'Ticket::EventModulePost', ); Example 1 XML config: Example event module updates the example escalation index. Example Core::Example Kernel::System::Example::Event::ExampleEscalationIndex (ExampleSLAUpdate|ExampleQueueUpdate|ExampleStateUpdate|ExampleCreate) Some Option accessable via $Param{Config}->{SomeOption} in Run() of event module. (0|1) Example 2: $Self->EventHandlerInit( Config => 'ITSM::EventModule', ); Example 2 XML config: ITSM event module updates the history for Change and WorkOrder objects.. ITSM Change Management Core::ITSMEvent Kernel::System::ITSMChange::Event::HistoryAdd (ChangeUpdate|WorkOrderUpdate|ChangeAdd|WorkOrderAdd) Some Option accessable via $Param{Config}->{SomeOption} in Run() of event module. (0|1) ITSM event module updates the ConfigItem History. ITSM Configuration Management Core::ITSMEvent Kernel::System::ITSMConfigurationManagement::Event::HistoryAdd (ConfigItemUpdate|ConfigItemAdd) Some Option accessable via $Param{Config}->{SomeOption} in Run() of event module. (0|1) =cut sub EventHandlerInit { my ( $Self, %Param ) = @_; $Self->{EventHandlerInit} = \%Param; $Kernel::OM->ObjectRegisterEventHandler( EventHandler => $Self ); return 1; } =head2 EventHandler() call event handler, returns true if it was executed successfully. Example 1: my $Success = $EventHandler->EventHandler( Event => 'TicketStateUpdate', # event classification, passed to the configured event handlers Data => { # data payload for the event, passed to the configured event handlers TicketID => 123, }, UserID => 123, Transaction => 1, # optional, 0 or 1 ); In 'Transaction' mode, all events will be collected and executed together, usually in the destructor of your object. Example 2: my $Success = $EventHandler->EventHandler( Event => 'ChangeUpdate', Data => { ChangeID => 123, }, UserID => 123, ); =cut sub EventHandler { my ( $Self, %Param ) = @_; # check needed stuff for (qw(Data Event UserID)) { if ( !$Param{$_} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need $_!" ); return; } } # get configured modules my $Modules = $Kernel::OM->Get('Kernel::Config')->Get( $Self->{EventHandlerInit}->{Config} ); # return if there is no one return 1 if !$Modules; # remember events only on normal mode if ( !$Self->{EventHandlerTransaction} ) { push @{ $Self->{EventHandlerPipe} }, \%Param; } # get main object my $MainObject = $Kernel::OM->Get('Kernel::System::Main'); # load modules and execute MODULE: for my $Module ( sort keys %{$Modules} ) { # If the module has an event configuration, determine if it should be executed for this event, # and store the result in a small cache to avoid repetition on jobs involving many tickets. if ( !defined $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } ) { if ( !$Modules->{$Module}->{Event} ) { $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } = 1; } else { $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } = $Param{Event} =~ /$Modules->{$Module}->{Event}/; } } if ( $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } ) { if ( $Self->{EventHandlerTransaction} && !$Param{Transaction} ) { # This is a special case. A new event was fired during processing of # the queued events in transaction mode. This event must be immediately # processed. } else { # This is the regular case. A new event was fired in regular mode, or # we are processing a queued event in transaction mode. Only execute # this if the transaction settings of event and listener are the same. # skip if we are not in transaction mode, but module is in transaction next MODULE if !$Param{Transaction} && $Modules->{$Module}->{Transaction}; # skip if we are in transaction mode, but module is not in transaction next MODULE if $Param{Transaction} && !$Modules->{$Module}->{Transaction}; } # load event module next MODULE if !$MainObject->Require( $Modules->{$Module}->{Module} ); # execute event backend my $Generic = $Modules->{$Module}->{Module}->new(); $Generic->Run( %Param, Config => $Modules->{$Module}, ); } } return 1; } =head2 EventHandlerTransaction() handle all queued 'Transaction' events which were collected up to this point. $EventHandler->EventHandlerTransaction(); Call this method in the destructor of your object which inherits from Kernel::System::EventHandler, like this: sub DESTROY { my $Self = shift; # execute all transaction events $Self->EventHandlerTransaction(); return 1; } =cut sub EventHandlerTransaction { my ( $Self, %Param ) = @_; # remember, we are in destroy mode, do not execute new events $Self->{EventHandlerTransaction} = 1; # execute events on end of transaction if ( $Self->{EventHandlerPipe} ) { for my $Params ( @{ $Self->{EventHandlerPipe} } ) { $Self->EventHandler( %Param, %{$Params}, Transaction => 1, ); } # delete event pipe $Self->{EventHandlerPipe} = undef; } # reset transaction mode $Self->{EventHandlerTransaction} = 0; return 1; } =head2 EventHandlerHasQueuedTransactions() Return a true value if there are queued transactions, which C handles, when called. =cut sub EventHandlerHasQueuedTransactions { my ( $Self, %Param ) = @_; return IsArrayRefWithData( $Self->{EventHandlerPipe} ); } 1; =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). This software comes with ABSOLUTELY NO WARRANTY. For details, see the enclosed file COPYING for license information (GPL). If you did not receive this file, see L. =cut