# HG changeset patch # User cin # Date 1446079825 -10800 # Node ID cc2cf8c0edc205844da65584373de4c9bd2b6b19 # Parent 3d24b10dd0d5a35782badcd8de9c65694722119f sync diff -r 3d24b10dd0d5 -r cc2cf8c0edc2 lib/IMPL/Config/ActivationContext.pm --- a/lib/IMPL/Config/ActivationContext.pm Tue Oct 20 07:32:55 2015 +0300 +++ b/lib/IMPL/Config/ActivationContext.pm Thu Oct 29 03:50:25 2015 +0300 @@ -1,10 +1,12 @@ package IMPL::Config::ActivationContext; +use IMPL::lang qw(:base); use IMPL::Const qw(:prop); use IMPL::Exception(); use IMPL::declare { require => { - PropertyBag => 'IMPL::Config::ServicesBag' + Bag => 'IMPL::Config::ServicesBag', + ServiceNotFoundException => 'IMPL::Config::ServiceNotFoundException', }, base => { 'IMPL::Object' => '@_' @@ -21,7 +23,9 @@ my ( $this, $container ) = @_; $this->container($container) - or die IMPL::InvalidArgumentException('container'); + or die IMPL::InvalidArgumentException->new('container'); + $this->_cache({}); + $this->_stack([]); } sub EnterScope { @@ -30,29 +34,67 @@ my $info = { name => $name }; if ($services) { - $info->{services} = $this->_services; + die IMPL::InvalidArgumentException->new( + services => 'An array is required' ) + unless isarray($services); + + my $bag = $this->container->serviceCache->{ ref($services) }; + + unless ($bag) { + my $container = $this->container; + $bag = Bag->new( $this->_services ); - $this->_services( $services ); + $bag->Register( + $container->GetLinearRoleHash( $_->{role}, $_->{descriptor} ) ) + foreach @$services; + + $container->serviceCache->{ ref($services) } = $bag; + } + + $info->{services} = $this->_services; + $this->_services($bag); } - $this->_stack->Push($info); + push @{$this->_stack}, $info; } sub LeaveScope { my ($this) = @_; - my $info = $this->_stack->Pop() - or die IMPL::InvalidOperationException(); + my $info = pop @{$this->_stack} + or die IMPL::InvalidOperationException->new(); + + $this->_services( $info->{services} ) if $info->{services}; +} - if ( $info->{services} ) $this->_services( $info->{services} ); +sub GuardScope { + my ( $this, $name, $services, $action ) = @_; + + $this->EnterScope( $name, $service ); + eval { $action ($this) if $action; } my $err = $@; + $this->LeaveScope(); + die $err if $err; } sub Resolve { - my ($this, $role, %opts) = @_; + my ( $this, $role, %opts ) = @_; + + my $d = $this->_services->Reolve($role); + + unless($d) { + die ServiceNotFoundException->new($role) unless $opts{optional}; + return $opts{default}; + } else { + return $d->Activate($this); + } } sub Clone { my ($this) = @_; + + my $clone = SELF->new($this->container); + + $clone->_ } 1; @@ -72,6 +114,6 @@ =head2 METHODS -=head3 GetService($serviceId) +=head3 Resolve($serviceId) =cut diff -r 3d24b10dd0d5 -r cc2cf8c0edc2 lib/IMPL/Config/ActivationException.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/IMPL/Config/ActivationException.pm Thu Oct 29 03:50:25 2015 +0300 @@ -0,0 +1,31 @@ +package IMPL::Config::ActivationException; +use strict; + +use IMPL::declare { + base => [ + 'IMPL::AppException' => undef + ], + props => [ + activationStack => 'ro', + serviceName => 'ro', + innerException => 'ro', + reason => 'ro' + ] +}; + +use IMPL::Resources::Strings { + message => "Error activating %serviceName%: %reason%" +}; + +sub CTOR { + my ( $this, %args ) = @_; + + $this->$_( $args{$_} ) foreach grep exists $args{$_}, qw( + activationStack + serviceName + innerException + reason + ); +} + +1; diff -r 3d24b10dd0d5 -r cc2cf8c0edc2 lib/IMPL/Config/ReferenceDescriptor.pm --- a/lib/IMPL/Config/ReferenceDescriptor.pm Tue Oct 20 07:32:55 2015 +0300 +++ b/lib/IMPL/Config/ReferenceDescriptor.pm Thu Oct 29 03:50:25 2015 +0300 @@ -23,6 +23,11 @@ $this->reference($ref) or die IMPL::InvalidArgumentException->new('ref'); + $this->lazy( $opts{lazy} ) if $opts{lazy}; + $this->optional( $opts{optional} ) if $opts{optional}; + $this->default( $opts{default} ) + if $opts{optional} and exists $opts{default}; + $this->_name( 'ref ' . $ref ); } @@ -50,3 +55,34 @@ } 1; + +__END__ + +=pod + +=head1 NAME + +C - A descriptor which is points to the other service + +=head1 MEMBERS + +=head2 PROPS + +=head3 reference + +=head3 lazy + +=head3 optional + +=head3 default + +=head2 METHODS + +=head3 CTOR($ref, %opts) + +=head3 Activate($context) + +Returns a result of the activation of the service specified by the C property. + +If the reference is lazy the method returns a closure.The C<$context> will be cloned and the clone will be used to create the closure. +=cut diff -r 3d24b10dd0d5 -r cc2cf8c0edc2 lib/IMPL/Config/ServiceDescriptor.pm --- a/lib/IMPL/Config/ServiceDescriptor.pm Tue Oct 20 07:32:55 2015 +0300 +++ b/lib/IMPL/Config/ServiceDescriptor.pm Thu Oct 29 03:50:25 2015 +0300 @@ -5,7 +5,8 @@ use IMPL::Exception(); use IMPL::declare { require => { - Bag => 'IMPL::Config::Bag' + Bag => 'IMPL::Config::Bag', + ActivationException => 'IMPL::Config::ActivationException' }, base => [ 'IMPL::Object' => undef, @@ -41,30 +42,36 @@ sub Activate { my ( $this, $context ) = @_; - $context->EnterScope( $this->_name, $this->services ); + my $instance; + $context->GuardScope( + $this->_name, + $this->services, + sub { - my $activation = $this->activation; - my $cache; + my $activation = $this->activation; + my $cache; - if ( $activation == IMPL::Config::Descriptor::ACTIVATE_SINGLETON ) { - $cache = $context->container->root->instances; - } - elsif ( $activation == IMPL::Config::Descriptor::ACTIVATE_CONTAINER ) { - $cache = $context->container->instances; - } - elsif ( $activation == IMPL::Config::Descriptor::ACTIVATE_CONTEXT ) { - $cache = $context->instances; - } + if ( $activation == IMPL::Config::Descriptor::ACTIVATE_SINGLETON ) { + $cache = $context->container->root->instances; + } + elsif ( + $activation == IMPL::Config::Descriptor::ACTIVATE_CONTAINER ) + { + $cache = $context->container->instances; + } + elsif ( $activation == IMPL::Config::Descriptor::ACTIVATE_CONTEXT ) + { + $cache = $context->instances; + } - my $instance = $cache->{ ref($this) } if $cache; + $instance = $cache->{ ref($this) } if $cache; + unless ($instance) { + $instance = $this->CreateInstance($context); + } - unless ($instance) { - $instance = $this->CreateInstance($context); - } - - $cache->{ ref($this) } = $instance if $cache; - - $context->LeaveScope(); + $cache->{ ref($this) } = $instance if $cache; + } + ); return $instance; } diff -r 3d24b10dd0d5 -r cc2cf8c0edc2 lib/IMPL/Config/ServiceNotFoundException.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/IMPL/Config/ServiceNotFoundException.pm Thu Oct 29 03:50:25 2015 +0300 @@ -0,0 +1,25 @@ +package IMPL::Config::ServiceNotFoundException; +use strict; + +use IMPL::declare { + base => [ + 'IMPL::AppException' => undef + ], + props => [ + serviceName => 'ro', + ] +}; + +use IMPL::Resources::Strings { + message => "Service %serviceName% not found" +}; + +sub CTOR { + my ( $this, %args ) = @_; + + $this->$_( $args{$_} ) foreach grep exists $args{$_}, qw( + serviceName + ); +} + +1;