Mercurial > pub > Impl
view lib/IMPL/Config/ServicesBag.pm @ 409:f7eeafbd33da ref20150831
sync
author | cin |
---|---|
date | Sun, 13 Sep 2015 19:30:49 +0300 |
parents | c6e90e02dd17 |
children | ee36115f6a34 |
line wrap: on
line source
package IMPL::Config::ServicesBag; require v5.9.5; use mro; use IMPL::Const qw(:prop); use IMPL::declare { base => [ 'IMPL::Object' => undef ], props => [ _prototype => PROP_RW, _nameMap => PROP_RW, _typeMap => PROP_RW, _props => PROP_RW, ] }; sub CTOR { my ( $this, $prototype ) = @_; $this->_prototype($prototype) if $prototype; $this->_nameMap( {} ); $this->_typeMap( {} ); } sub GetDescriptorByName { my ( $this, $name ) = @_; my $d = $this->_nameMap->{$name}; return $d if $d and $d->{valid}; my $parent = $this->_prototype; if ( $parent and $d = $parent->GetDescriptorByName($name) ) { return $this->_nameMap->{$name} = $d; } return undef; } sub GetDescriptorByType { my ( $this, $type ) = @_; my $d = $this->_typeMap->{$type}; return $d if $d and $d->{valid}; my $parent = $this->_prototype; if ( $parent and $d = $parent->GetDescriptorByType($type) ) { return $this->_typeMap->{$type} = $d; } return undef; } sub RegisterValue { my ( $this, $value, $name, $type ) = @_; my $d = { owner => $this, value => $value, valid => 1 }; if ($type) { my $map = $this->_typeMap; my $isa = mro::get_linear_isa($type); $d->{isa} = $isa; # the service record which is superseded by the current one my $replaces = $this->GetDescriptorByType($type); foreach my $t (@$isa) { if ( my $prev = $this->GetDescriptorByType($t) ) { # keep previous registrations if they are valid next if not $replaces or $prev != $replaces; } $map->{$t} = $d; } if ($replaces) { # invalidate cache $replaces->{owner}->UpdateDescriptor($replaces); } } if ($name) { my $prev = $this->_nameMap->{$name}; $d->{name} = $name; $this->_nameMap->{$name} = $d; $prev->{owner}->UpdateDescriptor($prev) if $prev; } return $d; } sub UpdateDescriptor { my ( $this, $d ) = @_; my $d2 = {}; # copy descriptor while ( my ( $k, $v ) = each %$d ) { $d2->{$k} = $v; } # update named entries my $name = $d->{name}; if ( $name and $this->_nameMap->{$name} == $d ) { $this->_nameMap->{$name} = $d2; } # update type entries if ( my $isa = $d->{isa} ) { my $map = $this->_typeMap; foreach my $t (@$isa) { next unless $map->{$t} == $d; $map->{$t} = $d2; } } $d->{valid} = 0; } 1; __END__ =pod =head1 NAME =head1 SYNOPSIS =head1 DESCRIPTION Коллекция сервисов построена на прототиптровании экземпляров, т.е. при создании новой коллекции может указваться базовая коллекция в которой будет происходить поиск сервисов в случае их отсутсвия в основной. Для оптимизации данного процесса сервисы кешируются, чтобы избежать можестрвенных операций поиска по иерархии коллекций, для этого каждый сервис описывается дескриптором: =over =item * isa массив типов сервиса, если он регистрировался как сервис =item * value значение =item * valid признак того, что дескриптор действителен =item * owner коллекция, которая создала данный дескриптор =back Если запрашиваемый десриптор не найден это является ошибкой, поэтому негативные ответы не кешируются =cut