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::EventHandler; 10## nofilter(TidyAll::Plugin::OTRS::Perl::Pod::FunctionPod) 11 12use strict; 13use warnings; 14 15use Kernel::System::VariableCheck qw(IsArrayRefWithData); 16 17our $ObjectManagerDisabled = 1; 18 19=head1 NAME 20 21Kernel::System::EventHandler - event handler interface 22 23=head1 DESCRIPTION 24 25Inherit from this class if you want to use events there. 26 27 use parent qw(Kernel::System::EventHandler); 28 29In your class, have to call L</EventHandlerInit()> first. 30 31Then, to register events as they occur, use the L</EventHandler()> 32method. It will call the event handler modules which are registered 33for the given event, or queue them for later execution (so-called 34'Transaction' events). 35 36In the destructor, you should add a call to L</EventHandlerTransaction()> 37to make sure that also C<Transaction> events will be executed correctly. 38This is only necessary if you use C<Transaction> events in your class. 39 40=head1 PUBLIC INTERFACE 41 42=head2 EventHandlerInit() 43 44Call this to initialize the event handling mechanisms to work 45correctly with your object. 46 47 $Self->EventHandlerInit( 48 # name of configured event modules 49 Config => 'Example::EventModule', 50 ); 51 52Example 1: 53 54 $Self->EventHandlerInit( 55 Config => 'Ticket::EventModulePost', 56 ); 57 58Example 1 XML config: 59 60 <ConfigItem Name="Example::EventModule###99-EscalationIndex" Required="0" Valid="1"> 61 <Description Translatable="1">Example event module updates the example escalation index.</Description> 62 <Group>Example</Group> 63 <SubGroup>Core::Example</SubGroup> 64 <Setting> 65 <Hash> 66 <Item Key="Module">Kernel::System::Example::Event::ExampleEscalationIndex</Item> 67 <Item Key="Event">(ExampleSLAUpdate|ExampleQueueUpdate|ExampleStateUpdate|ExampleCreate)</Item> 68 <Item Key="SomeOption">Some Option accessable via $Param{Config}->{SomeOption} in Run() of event module.</Item> 69 <Item Key="Transaction">(0|1)</Item> 70 </Hash> 71 </Setting> 72 </ConfigItem> 73 74Example 2: 75 76 $Self->EventHandlerInit( 77 Config => 'ITSM::EventModule', 78 ); 79 80Example 2 XML config: 81 82 <ConfigItem Name="ITSM::EventModule###01-HistoryAdd" Required="0" Valid="1"> 83 <Description Translatable="1">ITSM event module updates the history for Change and WorkOrder objects..</Description> 84 <Group>ITSM Change Management</Group> 85 <SubGroup>Core::ITSMEvent</SubGroup> 86 <Setting> 87 <Hash> 88 <Item Key="Module">Kernel::System::ITSMChange::Event::HistoryAdd</Item> 89 <Item Key="Event">(ChangeUpdate|WorkOrderUpdate|ChangeAdd|WorkOrderAdd)</Item> 90 <Item Key="SomeOption">Some Option accessable via $Param{Config}->{SomeOption} in Run() of event module.</Item> 91 <Item Key="Transaction">(0|1)</Item> 92 </Hash> 93 </Setting> 94 </ConfigItem> 95 <ConfigItem Name="ITSM::EventModule###02-HistoryAdd" Required="0" Valid="1"> 96 <Description Translatable="1">ITSM event module updates the ConfigItem History.</Description> 97 <Group>ITSM Configuration Management</Group> 98 <SubGroup>Core::ITSMEvent</SubGroup> 99 <Setting> 100 <Hash> 101 <Item Key="Module">Kernel::System::ITSMConfigurationManagement::Event::HistoryAdd</Item> 102 <Item Key="Event">(ConfigItemUpdate|ConfigItemAdd)</Item> 103 <Item Key="SomeOption">Some Option accessable via $Param{Config}->{SomeOption} in Run() of event module.</Item> 104 <Item Key="Transaction">(0|1)</Item> 105 </Hash> 106 </Setting> 107 </ConfigItem> 108 109=cut 110 111sub EventHandlerInit { 112 my ( $Self, %Param ) = @_; 113 114 $Self->{EventHandlerInit} = \%Param; 115 $Kernel::OM->ObjectRegisterEventHandler( EventHandler => $Self ); 116 117 return 1; 118} 119 120=head2 EventHandler() 121 122call event handler, returns true if it was executed successfully. 123 124Example 1: 125 126 my $Success = $EventHandler->EventHandler( 127 Event => 'TicketStateUpdate', # event classification, passed to the configured event handlers 128 Data => { # data payload for the event, passed to the configured event handlers 129 TicketID => 123, 130 }, 131 UserID => 123, 132 Transaction => 1, # optional, 0 or 1 133 ); 134 135In 'Transaction' mode, all events will be collected and executed together, 136usually in the destructor of your object. 137 138Example 2: 139 140 my $Success = $EventHandler->EventHandler( 141 Event => 'ChangeUpdate', 142 Data => { 143 ChangeID => 123, 144 }, 145 UserID => 123, 146 ); 147 148=cut 149 150sub EventHandler { 151 my ( $Self, %Param ) = @_; 152 153 # check needed stuff 154 for (qw(Data Event UserID)) { 155 if ( !$Param{$_} ) { 156 $Kernel::OM->Get('Kernel::System::Log')->Log( 157 Priority => 'error', 158 Message => "Need $_!" 159 ); 160 return; 161 } 162 } 163 164 # get configured modules 165 my $Modules = $Kernel::OM->Get('Kernel::Config')->Get( $Self->{EventHandlerInit}->{Config} ); 166 167 # return if there is no one 168 return 1 if !$Modules; 169 170 # remember events only on normal mode 171 if ( !$Self->{EventHandlerTransaction} ) { 172 push @{ $Self->{EventHandlerPipe} }, \%Param; 173 } 174 175 # get main object 176 my $MainObject = $Kernel::OM->Get('Kernel::System::Main'); 177 178 # load modules and execute 179 MODULE: 180 for my $Module ( sort keys %{$Modules} ) { 181 182 # If the module has an event configuration, determine if it should be executed for this event, 183 # and store the result in a small cache to avoid repetition on jobs involving many tickets. 184 if ( !defined $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } ) { 185 if ( !$Modules->{$Module}->{Event} ) { 186 $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } = 1; 187 } 188 else { 189 $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } = 190 $Param{Event} =~ /$Modules->{$Module}->{Event}/; 191 } 192 } 193 194 if ( $Self->{ExecuteModuleOnEvent}->{$Module}->{ $Param{Event} } ) { 195 196 if ( $Self->{EventHandlerTransaction} && !$Param{Transaction} ) { 197 198 # This is a special case. A new event was fired during processing of 199 # the queued events in transaction mode. This event must be immediately 200 # processed. 201 } 202 else { 203 204 # This is the regular case. A new event was fired in regular mode, or 205 # we are processing a queued event in transaction mode. Only execute 206 # this if the transaction settings of event and listener are the same. 207 208 # skip if we are not in transaction mode, but module is in transaction 209 next MODULE if !$Param{Transaction} && $Modules->{$Module}->{Transaction}; 210 211 # skip if we are in transaction mode, but module is not in transaction 212 next MODULE if $Param{Transaction} && !$Modules->{$Module}->{Transaction}; 213 } 214 215 # load event module 216 next MODULE if !$MainObject->Require( $Modules->{$Module}->{Module} ); 217 218 # execute event backend 219 my $Generic = $Modules->{$Module}->{Module}->new(); 220 221 $Generic->Run( 222 %Param, 223 Config => $Modules->{$Module}, 224 ); 225 } 226 } 227 228 return 1; 229} 230 231=head2 EventHandlerTransaction() 232 233handle all queued 'Transaction' events which were collected up to this point. 234 235 $EventHandler->EventHandlerTransaction(); 236 237Call this method in the destructor of your object which inherits from 238Kernel::System::EventHandler, like this: 239 240 sub DESTROY { 241 my $Self = shift; 242 243 # execute all transaction events 244 $Self->EventHandlerTransaction(); 245 246 return 1; 247 } 248 249=cut 250 251sub EventHandlerTransaction { 252 my ( $Self, %Param ) = @_; 253 254 # remember, we are in destroy mode, do not execute new events 255 $Self->{EventHandlerTransaction} = 1; 256 257 # execute events on end of transaction 258 if ( $Self->{EventHandlerPipe} ) { 259 260 for my $Params ( @{ $Self->{EventHandlerPipe} } ) { 261 $Self->EventHandler( 262 %Param, 263 %{$Params}, 264 Transaction => 1, 265 ); 266 } 267 268 # delete event pipe 269 $Self->{EventHandlerPipe} = undef; 270 } 271 272 # reset transaction mode 273 $Self->{EventHandlerTransaction} = 0; 274 275 return 1; 276} 277 278=head2 EventHandlerHasQueuedTransactions() 279 280Return a true value if there are queued transactions, which 281C<EventHandlerTransaction> handles, when called. 282 283=cut 284 285sub EventHandlerHasQueuedTransactions { 286 my ( $Self, %Param ) = @_; 287 288 return IsArrayRefWithData( $Self->{EventHandlerPipe} ); 289} 290 2911; 292 293=head1 TERMS AND CONDITIONS 294 295This software is part of the OTRS project (L<https://otrs.org/>). 296 297This software comes with ABSOLUTELY NO WARRANTY. For details, see 298the enclosed file COPYING for license information (GPL). If you 299did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 300 301=cut 302